【问题标题】:C# How can I make sure to execute awaitable operations in a single threadC#如何确保在单个线程中执行等待操作
【发布时间】:2019-06-21 17:59:20
【问题描述】:

我正在构建一个 UWP 应用程序,它显然包含几个对异步方法的等待调用。

在其中一个事件处理程序中,我需要确保调用链在单个线程中执行。

我试图通过等待并获得结果来制作我需要的异步方法的“同步”版本,如下所示:

public static T Sync<T>(this Task<T> task)
{
    if (task == null)
        return default(T);
    return task.ConfigureAwait(false).GetAwaiter().GetResult();
}

甚至更残酷:

    public static T Sync<T>(this Task<T> task)
    {
        if (task == null)
            return default(T);
        task.Wait();
        return task.Result;
    }

但我遇到了其他几个博客中描述的死锁问题,因为我在 UI 线程上运行。

有没有办法实现我的目标?

【问题讨论】:

  • 如果异步调用使用.ConfigureAwait(false),您无能为力。如果他们不这样做,他们的延续将在 UI 线程上运行,所以你已经在一个线程上
  • 我不害怕继续,我想在 UI 线程中,我想避免在等待时,另一个异步调用会改变我的状态。基本上我想将我的完整调用链包装成一个单线程操作。
  • 异步代码将使用 SynchronizationContext.Current 属性,因此您可以创建一个自定义类来处理线程中的 Post/Send 方法,但据我所知 UWP 框架已经有一个自定义在(单个)UI 线程中运行所有异步代码的上下文,所以我不明白你的问题? docs.microsoft.com/en-us/dotnet/api/…

标签: c# multithreading uwp async-await deadlock


【解决方案1】:

如何确保在单个线程中执行等待操作

正如其他人所指出的,默认情况下,UI 线程上的async/await在单个线程上执行所有延续。

我想避免在等待时,另一个异步调用会改变我的状态。

适当的解决方案是修复你的逻辑。任何替代方案(尤其是使 UI 线程无响应)都会降低您的用户体验,并可能阻止您的应用在商店中被接受。

也就是说,如果你绝对确定你想走这条路而不是一开始就修复你的代码,你有两个主要选择:

  1. 使所有代码同步。它将在 UI 线程上运行并根据需要阻止它。
  2. 运行嵌套消息循环。我不确定 UWP 是否支持此功能;您可能可以使用我的AsyncContext 来完成一些工作。

同样,两种这些解决方案都会使您的 UI 无响应,从而降低您的用户体验并可能导致商店拒绝。

【讨论】:

    【解决方案2】:

    如果您只关心对状态的序列化访问(即您一次只需要一个线程修改状态),您可以使用 .NET 中内置的众多同步原语之一来实现这一点。

    lock 语句是最简单的工具之一。

    当然,这会产生阻止您的Tasks 的副作用,这可能不适合您的应用程序。但是"async" locks 有一些可用的实现。

    【讨论】:

    • 感谢@Joseph,但不幸的是,这并不容易:每当我的代码中有等待调用时,我都会在任务列表中看到创建并启动了一个新任务。这使我的链成为多线程,这是我想要避免的。
    • await 调用必须在任务中运行,没有其他等待它工作,因为您当前的线程代码在调用后继续。但是任务使用“回调”来运行实际代码,并且这些“回调”在 SynchronizationContext.Current 上下文中运行,“默认”上下文可以在不同的任务/线程中运行,但大多数 UI 框架(例如 WPF)设置自定义上下文,以便所有任务回调将在(主)UI 线程中运行,因此异步/等待“链”的每个代码也将在 UI 线程中运行(通过任务回调)
    • "每当我的代码中有等待调用时,我都会在任务列表中看到创建并启动了 new task。这使我的链 multi-thread" - Task 是一个更高级别的概念,不是一个线程。两个Tasks 可能会也可能不会在同一个线程中执行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-14
    相关资源
    最近更新 更多