简体   繁体   English

C# 转换异步代码以在特定方法(Constructor/Main/PropertyGetter/PropertySetter)中运行同步而不会出现死锁

[英]C# Convert async code to run sync in certain method(Constructor/Main/PropertyGetter/PropertySetter) without possibility of deadlock

I have a bunch of async code, I have tried to expand my asyc code as large as possible in my codebase.我有一堆异步代码,我试图在我的代码库中尽可能大地扩展我的异步代码。 I am here looking for an safe approach to convert async code to async (wait it finish then return result).我在这里寻找一种将异步代码转换为异步代码的安全方法(等待它完成然后返回结果)。 I have tied looking on the inte.net but they either way to complex or may cause deadlocks.我已经在 inte.net 上查看过,但它们要么很复杂,要么可能导致死锁。

Here is my code:这是我的代码:

 protected virtual DbData GetDbData()
 {           
    return StorageProvider.RefreshAsync().Result;       
 }

The GetDbData will be used as a property getter something like: GetDbData 将用作属性获取器,例如:

 public override DbData Data
 {
     get => GetDbData();
     set => SetDbData(value);
 }

and in constructor并在构造函数中

public CachedDataManager(IStorageProvider storageProvider) : base(storageProvider)
{
   _cachedData = StorageProvider.RefreshAsync().Result;       
}

or for the async method without return value或者对于没有返回值的异步方法

public CachedDataManager(IStorageProvider storageProvider) : base(storageProvider)
{          
    DoSomeWorkAsync().GetAwaiter().GetResult();
}

private Task DoSomeWorkAsync()
{
   //Assume heavy load.
   Task.Delay(5000);
   return Task.CompletedTask;          
}

Result may causing a deadlock because of the SynchronizationContext when calling in the UI thead (what I know)在 UI thead 中调用时,结果可能会由于SynchronizationContext而导致deadlock (据我所知)

All the other solution told me to expand async code as far as possible, I tried, but I can't do it with constructor/property getter所有其他解决方案都告诉我尽可能扩展async代码,我试过了,但我不能用构造函数/属性获取器来做

Are there exist some solution similar to Task.Result / Task.Wait / Task.RunSynchronously that does not causes any problems(eg deadlock)?是否存在类似于Task.Result / Task.Wait / Task.RunSynchronously的解决方案,不会导致任何问题(例如死锁)?

Also I am not sure about DoSomeWorkAsync().GetAwaiter().GetResult();我也不确定DoSomeWorkAsync().GetAwaiter().GetResult(); it does causes problems with SynchronizationContext or not.它确实会导致SynchronizationContext出现问题。 I am a noob on this.我对此一窍不通。 Please help请帮忙

A task (what async methods return) can contain every type of logic.任务(异步方法返回的内容)可以包含每种类型的逻辑。 Suppose you are calling an async Task method from the Thread A, and you want to synchronously wait for the task to complete.假设您正在从线程 A 调用异步任务方法,并且您希望同步等待任务完成。 Now let's think carefully what could be the conditions for a deadlock: basically we have to guarantee that the Task do not schedule anything "asynchronously" on the Thread A. If that's the case you can safely call task.GetAwaiter().GetResult().现在让我们仔细想想死锁的条件是什么:基本上我们必须保证任务不会在线程 A 上“异步”安排任何事情。如果是这种情况,您可以安全地调用 task.GetAwaiter().GetResult() . If not you can't.如果不是,你不能。 It's a conceptual limit.这是概念上的限制。 There is not a general way to avoid deadlocks.没有避免死锁的通用方法。

For example suppose that the Thread A is the UI thread.例如,假设线程 A 是 UI 线程。 If the async Task contains a "real" await operation (that is, an await over a Task that is not completed yet, such as Task.Delay(100)), we are already in a bad spot: why?如果异步任务包含一个“真正的”等待操作(即等待尚未完成的任务,例如 Task.Delay(100)),我们就已经处于困境:为什么? Because the code after the await is wrapped into an Action and scheduled through the Synchronization Context in the UI Thread.因为await之后的代码被包装成一个Action,通过UI Thread中的Synchronization Context进行调度。 So the task is waiting for some code to execute in the UI thread, but the UI thread is waiting for the task to complete所以任务在UI线程中等待一些代码执行,但是UI线程在等待任务完成

Another example: suppouse the Task method we are awaiting is not async (so contains synchronous code, like Task.Run(VoidMethod)) and that at some point there is a call to Dispatcher.Invoke().另一个例子:假设我们正在等待的 Task 方法不是异步的(因此包含同步代码,如 Task.Run(VoidMethod)),并且在某个时刻有对 Dispatcher.Invoke() 的调用。 We still have a deadlock: the task to complete should wait for some code to be executed on the UI Thread.我们仍然有一个僵局:要完成的任务应该等待一些代码在 UI 线程上执行。 But the UI Thread is waiting for that task to complete..但是 UI 线程正在等待该任务完成。

Side note.边注。 While in the first example we can do some tricks such as change the Synchronization context temporarily in order to avoid the continuations to run on the UI Thread, in the second example there are no chance to make it work, it's conceptually wrong if you thing about it.虽然在第一个示例中我们可以做一些技巧,例如临时更改同步上下文以避免在 UI 线程上运行延续,但在第二个示例中没有机会让它工作,如果你考虑它在概念上是错误的它。 So there isn't a general way.所以没有通用的方法。

It really depends.这真的取决于。

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

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