【问题标题】:Set maximum runtime of a method设置方法的最大运行时间
【发布时间】:2020-06-29 21:32:49
【问题描述】:

如果我有一个方法想要执行一些(可能)长时间运行的函数,并且我想限制它的执行时间,我一直在使用这种模式(请原谅代码中的任何错误,键入手动,而不是在 IDE 中,这是对较大代码段的简化)。

public string GetHello()
{
    var task = Task.Run(() => 
    {
        // do something long running
        return "Hello";
    });

    bool success = task.Wait(TimeSpan.FromMilliseconds(1000));

    if (success)
    {
        return task.Result;
    }
    else
    {
        throw new TimeoutException("Timed out.");
    }
}

如果我想在异步容量中使用GetHello 方法,即public async Task<string> GetHello(),我将如何在希望保留类似模式的同时做到这一点?我有以下内容,但我收到了关于 This async method lacks 'await' operators and will run synchronously 的编译器警告。

public async Task<string> GetHello()
{
    var task = Task.Run(async () => 
    {
        // await something long running
        return "Hello";
    });

    bool success = task.Wait(TimeSpan.FromMilliseconds(1000));

    if (success)
    {
        return task.Result;
    }
    else
    {
        throw new TimeoutException("Timed out.");
    }
}

我只是不知道如何更改此设置或将 await 放在何处以使其按预期工作。

【问题讨论】:

  • 您可以添加CancellationTokenSource。阅读文档Task.Run :: CancellationTokenSource(Int32) 初始化 CancellationTokenSource 类的新实例,该实例将在指定的延迟(以毫秒为单位)后取消。
  • 我知道 CancellationTokenSource 的工作原理 - 这与回答我的问题有什么关系?
  • Guru Stron 实现了我提到的CancellationTokenSource。这就是它的相关性
  • 抛出 TimeoutException 不一定会阻止 task 继续运行。这就是你的想法吗?
  • @Barns 将我指向文档并没有提供答案,但无论如何谢谢。

标签: c# multithreading task


【解决方案1】:

您可以结合使用 CancellationToken 和 awaitable Task.WhenAny 来实现所需的行为:

public async Task<string> GetHello()
{
    var cts = new CancellationTokenSource();
    var task = Task.Run(async () =>
    {
        // await something long running and pass/use cts.Token here too
        return "Hello";
    }, cts.Token);

    var delay = Task.Delay(1000, cts.Token);

    var finishedFirst = await Task.WhenAny(task, delay);
    cts.Cancel();
    if (finishedFirst == task)
    {
        return task.Result;
    }
    else
    {
        throw new TimeoutException("Timed out.");
    }
} 

【讨论】:

  • 可能更重要的是异步方法检查令牌并在它被取消时中止。否则在抛出超时异常后,长时间运行的工作可能仍然运行long
  • 那么在else 块中添加cts.Cancel()
  • @joelc 不在else 块中,到await something long running
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-04
  • 1970-01-01
相关资源
最近更新 更多