C# MongoDB 2.0驱动程序和非异步代码可能出现死锁

C# MongoDB 2.0驱动程序和非异步代码可能出现死锁,c#,multithreading,mongodb,asynchronous,C#,Multithreading,Mongodb,Asynchronous,我们有一个ASP.NETMVC网站,并将所有文本存储在MongoDB中。类本地化TextManager负责提供这些文本并在内部缓存它们。通常,此方法非常快(

我们有一个ASP.NETMVC网站,并将所有文本存储在MongoDB中。类本地化TextManager负责提供这些文本并在内部缓存它们。通常,此方法非常快(<5ms),如果结果在缓存中,则速度更快

我们有两种方法:GetString和GetStringAsync。GetStringAsync是首选,但我们在Razor中使用GetString方法,例如,在一些不在异步上下文中的罕见情况下

MongoDB有一个异步驱动程序,我需要非同步地实现它。因此,我们尝试了几种方法。我确保在代码中的任何地方设置ConfigureAwait(false)

FindOrAddTextFromRepositoryAsync(key).Result;
Task.Run(async () => await FindOrAddTextFromRepositoryAsync(key)).Result;
Task.Run(async () => await FindOrAddTextFromRepositoryAsync(key).ConfigureAwait(false)).Result;
我知道我不需要在任务中使用ConfigureAwait(false)(因为不应该有同步上下文)

我刚刚部署了该网站,部署后它会挂起。在多次重新启动过程后,它开始工作。我以前做过转储,发现有很多这样的方法调用:

w3wp(4).DMP中的以下线程正在System.Threading.Monitor.Wait中等待~100线程阻塞:

mscorlib_ni!System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)+3ec 
mscorlib_ni!System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)+db 
mscorlib_ni!System.Threading.Tasks.Task.InternalWait(Int32, System.Threading.CancellationToken)+24a 
mscorlib_ni!System.Threading.Tasks.Task`1[[System.__Canon, mscorlib]].GetResultCore(Boolean)+36 
GP.Components.Globalization.LocalizationTextManager.GetString(System.String, System.String)+2f4 
GP.Components.Globalization.LocalizationTextManager.GetString(System.String, System.Globalization.CultureInfo)+8a 

我的问题是:我如何正确地实现它?另一个想法是使用
LimitedThreadsScheduler
,以确保它不会严重并行化。

代码中的主要问题是代码不是异步的

对于您创建的每个
任务
,您都显式调用该属性

这将导致阻塞当前线程,直到任务完成

如果需要处理
Task.Complete事件
,可以使用
Task
类的静态或静态方法。只是不要阻止您的任务:

.ContinueWith( (t) => { Console.WriteLine(t.Result); },
    TaskContinuationOptions.OnlyOnRanToCompletion);
或:

如我所见,在跟踪
GetString
中,非异步版本正在运行并等待结果,因此其他线程无法执行任何操作。我建议您尝试调整用于
任务的性能,并为不同的任务调度器拆分同步和异步代码,以便它们不会相互阻塞。此处介绍了任务的其他选项:


至于你最后的问题,这里有一篇关于的好文章,你可以试着从这里开始。

我知道,这正是我所做的;)用一些想法更新了答案about@VMAtm说清楚一点,你有什么建议?使用委托分配值,然后使用任务。是否有?我建议找出阻塞代码的位置,并尽可能将其删除<代码>等待。任何
仍会阻止正在执行的线程。如果只有一个消费者,那么锁定问题就会少一些。
.ContinueWith( (t) => { Console.WriteLine(t.Result); },
    TaskContinuationOptions.OnlyOnRanToCompletion);
Task.WaitAll(tasks);