我是asp.net核心和异步编程的新手。下面是我的代码
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var work = await TaskQueue.DequeueAsync(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
redirect(work);
}
}
public async Task redirect(Func<CancellationToken, Task> work)
{
await work();
}
所以在这里,当我运行程序并对其进行调试时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。 重定向方法仍然是异步的,它将等待工作方法。所以我认为它没有异步运行。
我希望当光标进入工作方法时,它将启动一个新任务(线程)。
答案 0 :(得分:2)
当我运行程序并对其进行调试时
您正在观察的行为是Visual Studio 尝试,对您有所帮助。它具有处理异步方法的特殊代码,因此,当您说“进入下一行”时,它不会突然转移到某些完全不相关的方法。它将转到该方法的下一行 。
我希望当光标进入工作方法时,它将启动一个新任务(线程)。
任务不是线程。特别是,sns.distplot(meanopa, hist=True, kde=True, bins=20, color = 'darkblue',
hist_kws={'edgecolor':'black'}, kde_kws={'linewidth': 4})
方法创建的任务不会在线程上运行;它们只是状态对象,可以在async
方法完成后通知其他代码。
我建议阅读我的async
intro,并紧跟async
best practices。
答案 1 :(得分:1)
您尝试使用Async-Await
的方式存在一些误解,网络上有足够的内容,以下是详细信息:
所以在这里,当我运行程序并对其进行调试时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。重定向方法仍然是异步的,它将等待工作方法。所以我认为它不是异步运行的
await
的作用是释放调用上下文,而处理在后台进行,这有助于系统保持响应速度,因此系统具有可伸缩性/线程池来满足进一步的请求,因此只有{{1} }不会阻塞调用线程/上下文,在调试器中(如您的代码所示)将等待完成。
现在
await
进行的处理是IO还是计算
如果它是work
,那就是真正在服务器上使用异步处理的地方,因为线程池线程已释放,并且如果与IO
一起使用,则不需要重新输入相同的上下文来处理响应,这是图书馆期望的。如果是计算的,那么它就可以像WPF这样的UI很好地工作,因为Ui线程保持响应能力,但是仍然可以从当前池中删除线程,并且可用性有限/稀缺。
关于您的代码
ConfigureAwait(false)
,而redirect(work)
又会调用await work
,它会释放调用方,但要等到下一次Async操作完成之前,被执行List<Task>
之类的集合中,当等待Task.WhenAll
时,就是所有聚合的任务都在一起,而您异步地等待单个代表Task
对于所有这些对象而言,仍然不能像当前代码中那样盲目地执行/调用,而是阻止完整的聚合列表,该列表由@TheGeneral在注释中指定,从而有助于更好地处理所有任务,因为所有任务在一起>
await work()
也不正确,编译错误,这需要一个取消令牌作为I / p参数redirect(work)
,整个调用链中都应异步等待代码的修改版本
假设您需要Task.WhenAll
并且您正在执行基于IO的异步操作,则以下应为您的代码:
protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken,CancellationToken stopWorkToken)
{
var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
List<Task> taskList = new List<Task>();
while (!stoppingQueueToken.IsCancellationRequested)
{
taskList.Add(redirect(work, stopWorkToken));
}
await Task.WhenAll(taskList);
}
public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stopWorkToken)
{
await work(stopWorkToken);
}
我已经为引入工作取消而引入了额外的取消令牌,因为工作处理仅在退出循环时才开始一次,在此之前它仅聚合任务,然后将它们一起在后台处理,并假定IO为最大效益。这里调试器也会阻塞,但是对于所有任务,只需一次调用
如果坚持使用当前代码,则只需进行以下更改:
protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken)
{
var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
List<Task> taskList = new List<Task>();
while (!stoppingQueueToken.IsCancellationRequested)
{
await redirect(work, stoppingQueueToken);
}
}
public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stoppingQueueToken)
{
await work(stoppingQueueToken);
}
更多细节
Task
和Thread
不同并且可以互换,多个任务可以在同一线程上执行ThrowIfCancellationRequested