繁体   English   中英

Task.Run与直接异步调用,用于启动长时间运行的异步方法

[英]Task.Run vs. direct async call for starting long-running async methods

有好几次,我发现自己编写了长时间运行的异步方法,比如轮询循环。 这些方法可能如下所示:

private async Task PollLoop()
{
    while (this.KeepPolling)
    {
        var response = await someHttpClient.GetAsync(...).ConfigureAwait(false);
        var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

        // do something with content

        await Task.Delay(timeBetweenPolls).ConfigureAwait(false);
    }
}

为此目的使用async的目的是我们不需要专用的轮询线程,但是(对我而言)逻辑比直接使用像计时器这样的东西更容易理解(也就是说,不需要担心重入)。

我的问题是,从同步上下文启动这样一个循环的首选方法是什么? 我能想到至少两种方法:

var pollingTask = Task.Run(async () => await this.PollLoop());

// or

var pollingTask = this.PollLoop();

无论哪种情况,我都可以使用ContinueWith()来响应异常。 我对这两种方法之间差异的主要理解是,第一个将首先在线程池线程上开始循环,而第二个将在当前线程上运行,直到第一个等待。 这是真的? 还有其他需要考虑的事项或更好的尝试方法吗?

我对这两种方法之间差异的主要理解是,第一个将首先在线程池线程上开始循环,而第二个将在当前线程上运行,直到第一个等待。 这是真的?

是。 异步方法在第一次等待尚未完成的等待时将其任务返回给其调用者。

按照惯例,大多数异步方法返回非常快。 您也可以,因为await someHttpClient.GetAsync将很快到达。

将这个异步方法的开头移到线程池上是没有意义的。 它增加了开销,几乎没有延迟。 它当然无助于吞吐量或扩展行为。

在这里使用异步lambda( Task.Run(async () => await this.PollLoop()) )特别无用。 它只是将PollLoop返回的任务包含在另一层任务中。 Task.Run(() => this.PollLoop())会更好。

我对这两种方法之间差异的主要理解是,第一个将首先在线程池线程上开始循环,而第二个将在当前线程上运行,直到第一个等待。 这是真的?

是的,这是真的。

在你的场景中,似乎没有必要使用Task.Run ,但是方法调用和第一个await之间几乎没有代码,所以PollLoop()几乎会立即返回。 不必要地将任务包装在另一个任务中只会降低代码的可读性并增加开销。 我宁愿使用第二种方法。

关于其他考虑因素(例如异常处理),我认为这两种方法是等效的。

为此目的使用async的目的是我们不需要专用的轮询线程,但是(对我而言)逻辑比直接使用像timer这样的东西更容易理解

作为旁注,这或多或少都是计时器无论如何都会做的。 实际上Task.Delay 使用计时器实现的!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM