【问题标题】:Calling asynchronous I/O method from sync code从同步代码调用异步 I/O 方法
【发布时间】:2022-01-12 21:18:20
【问题描述】:

我有这段代码(同步方式):

// ...
var processingTasks = Enumerable.Range(0, count)
    .Select(x => Task.Run(async () =>    
      await CallApiAndUpdateSthAsync(accounts[x], cancellationToken)))
    .ToList();

var processingTasksAggregate = Task.WhenAll(processingTasks);

Task.WaitAny(globalStatusMonitoringTask, processingTasksAggregate);

我对这部分特别感兴趣:

Task.Run(async () => await CallApiAndUpdateSthAsync(accounts[x], cancellationToken))

如果我删除了Task.Run,它会有所不同吗(从可能的死锁角度来看)? IE。改为:

CallApiAndUpdateSthAsync(accounts[x], cancellationToken)

我想删除它,因为在线程池中排队任务(通过Task.Run)似乎是多余的,但我的同事建议我不要这样做,因为可能会出现死锁

整个方法作为后台作业运行,类似于 Hangfire:

[编辑 1]:这是一个 .NET Framework(不是核心)应用程序。

【问题讨论】:

  • 如果不知道CallApiAndUpdateSthAsync() 的内容,就很难回答这个问题。但是,是的,它可以有所作为。
  • “切换到不同的线程池(通过Task.Run)”这是什么意思?
  • 我的意思是queueing the task on a thread pool - 我更新了问题。 (docs.microsoft.com/en-us/dotnet/api/…)
  • @JohnWu 我们不能黑箱CallApiAndUpdateSthAsync吗? IE。从那里调用了各种方法,很难具体说明正在发生的所有事情。这是一个在少数外部服务(API / Db)上调用等待的异步方法

标签: .net asynchronous task wait


【解决方案1】:

如果我删除 Task.Run 会有所不同(从可能的死锁角度来看)吗?

可能。 common deadlock 有两个部分(链接到我的博客):

  1. 阻塞异步代码。您的代码使用 Task.WaitAny 执行此操作。
  2. 一次只允许一个线程的上下文。

由于您的代码显然具有 (1),那么您可以得出结论,如果它具有 (2),它将死锁。可能导致死锁的常见上下文包括 ASP.NET pre-Core 和 GUI 线程上下文。如果您的应用没有一次一个线程的上下文,那么就不会出现死锁。

我想删除它,因为在线程池中排队任务(通过 Task.Run)似乎是多余的

不是真的。 “异步”并不意味着“在不同的线程上运行”,因此两者并不多余。问题是删除Task.Run 是否可行。它可能会,也可能不会。如果此代码在单线程上下文中运行,则删除 Task.Run 将导致死锁。如果CallApiAndUpdateSthAsync 可以同步运行(即,由于缓存命中),那么删除Task.Run 将导致调用串行而不是并行运行,这也可能是不可取的。

【讨论】:

    【解决方案2】:

    如果是asp.net core 应用程序(不仅仅是老派asp.net),则任务死锁没有问题。 SynchronizationContext(在没有ConfigureAwait(false) 的情况下会导致死锁)在asp.net core 中为空。 There isn’t a SynchronizationContext in ASP.NET Core.

    同样没有Task.Run - CallApiAndUpdateSthAsync 将在你的当前线程上执行,直到里面的第一个await。使用Task.Run - 整个CallApiAndUpdateSthAsync 将在您的主执行之外执行。您可以通过在CallApiAndUpdateSthAsync 的开头添加Task.Yield 来修复它。

    【讨论】:

    • 这是一个 .NET Framework 应用程序 - 我更新了问题
    • @MrPatience 是不是 asp.net 核心?因为您可以在完整的框架上创建 ASP.NET Core。
    • 如题,它是一个基于简单.NET Framework的后台处理中间件。 4.7.2 没有使用 ASP.NET 也没有使用 ASP.NET Core。
    • @MrPatience 根据您的描述,我认为您的代码中没有任何死锁的原因。也许你应该问问你的同事他的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    • 2010-12-29
    • 2017-09-23
    • 1970-01-01
    • 2016-01-06
    • 2018-04-06
    相关资源
    最近更新 更多