繁体   English   中英

如何在不阻塞主线程的情况下调用异步函数同步?

[英]How to call an async function synchronized without blocking the main thread?

我编写了一个简单的控制台应用程序来测试ConfigureAwait(false)以解决以同步方式调用异步函数的问题。 这就是我模拟事件并尝试以同步方式调用异步函数的方式。

 public static class Test2
    {
        private static EventHandler<int> _somethingEvent;

        public static void Run()
        {
            _somethingEvent += OnSomething;
            _somethingEvent(null, 10);
            Console.WriteLine("fetch some other resources");
            Console.ReadLine();
        }

        private static void OnSomething(object sender, int e)
        {
            Console.WriteLine($"passed value : {e}");
            FakeAsync().Wait();
        }

        private static async Task FakeAsync()
        {
            await Task.Delay(2000).ConfigureAwait(false);
            Console.WriteLine($"task completed");
        }
    }

代码的输出是这样的:

passed value : 10
task completed
fetch some other resources

当我像这样将OnSomething函数更改为 async void 时:

private static async void OnSomething(object sender, int e)
{
    Console.WriteLine($"passed value : {e}");
    await FakeAsync();
}

输出将更改为:

passed value : 10
fetch some other resources
task completed

您可以看到在任务完成部分之前获取了一些其他资源,这是我想要的结果。
我的问题是如何通过像我为OnSomething函数编写的第一个签名一样调用同步的异步函数来获得相同的结果?
在这种情况下,我如何使用ConfigureAwait(false)来帮助我? 或者也许我没有正确使用它。

我编写了一个简单的控制台应用程序来测试 ConfigureAwait(false) 以解决以同步方式调用异步函数的问题。

这有几个问题。

  1. ConfigureAwait(false)不是同步调用异步函数的“问题”的“修复”。 这是在某些情况下可行的一种可能的 hack ,但通常不建议这样做,因为您必须在该函数的整个传递闭包中的任何地方使用ConfigureAwait(false) - 包括第二方和第三方调用 - 如果您只是错过了一个,还是有死锁的可能。 从同步函数调用异步函数的问题的最佳解决方案是将调用函数更改为异步(走“一路异步”)。 有时这是不可能的,您需要hack ,但没有适用于所有场景的 hack 。
  2. 您试图避免死锁问题有两个组成部分:阻塞任务上的线程和单线程上下文。 控制台应用程序没有单线程上下文,因此在控制台应用程序中,就好像您的所有代码在任何地方都使用ConfigureAwait(false)

我的问题是如何通过像我为 OnSomething 函数编写的第一个签名一样调用同步的异步函数来获得相同的结果?

调用代码要么阻塞异步代码(例如Wait ),要么不阻塞(例如await )。 您无法阻止异步代码继续执行。 调用线程必须继续执行或阻塞; 它不能两者兼而有之。

这是因为当你调用_somethingEvent(null, 10); , OnSomething没有被等待,所以下面的Console.WriteLine("fetch some other resources"); 将允许在await FakeAsync();后直接运行await FakeAsync(); 被执行。

如果您在继续之前不需要等待OnSomething的完成,只需触发并忘记:

private static void OnSomething(object sender, int e)
{
    Console.WriteLine($"passed value : {e}");
    Task.Run(() => FakeAsync());
}

暂无
暂无

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

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