我有一些库(套接字网络)代码,它Task基于提供基于API的待处理请求响应TaskCompletionSource<T>.然而,TPL中的一个烦恼是,似乎不可能阻止同步延续.我会希望能够做的是两种:
TaskCompletionSource<T>不应该允许呼叫者附加TaskContinuationOptions.ExecuteSynchronously,或SetResult/ TrySetResult)以指定TaskContinuationOptions.ExecuteSynchronously应该忽略的方式具体来说,我遇到的问题是传入的数据正在由专用的阅读器处理,如果调用者可以附加,TaskContinuationOptions.ExecuteSynchronously他们可以阻止阅读器(这不仅影响它们).以前,我通过一些hackery解决了这个问题,它检测是否存在任何延续,如果它们将完成推送到ThreadPool,那么如果调用者已经使工作队列饱和,则会产生重大影响,因为完成将不会被处理及时.如果他们使用Task.Wait()(或类似),他们将基本上陷入僵局.同样,这就是读者使用专用线程而不是使用工作者的原因.
所以; 在我尝试唠叨TPL团队之前:我错过了一个选项吗?
关键点:
ThreadPool作为一个实现,因为它需要在池饱和时工作以下示例生成输出(排序可能因时间而异):
Continuation on: Main thread
Press [return]
Continuation on: Thread pool
Run Code Online (Sandbox Code Playgroud)
问题在于随机调用者设法在"主线程"上获得延续.在实际代码中,这将打断主要读者; 坏事!
码:
using System;
using System.Threading;
using System.Threading.Tasks;
static class Program
{
static void Identify()
{
var thread = Thread.CurrentThread;
string name = thread.IsThreadPoolThread
? "Thread pool" : thread.Name;
if (string.IsNullOrEmpty(name))
name = …Run Code Online (Sandbox Code Playgroud) 我在调用StackExchange.Redis时遇到了死锁情况.
我不确切知道发生了什么,这是非常令人沮丧的,我希望任何有助于解决或解决此问题的输入.
万一你也有这个问题,不想读这一切; 我建议你将尝试设置
PreserveAsyncOrder到false.Run Code Online (Sandbox Code Playgroud)ConnectionMultiplexer connection = ...; connection.PreserveAsyncOrder = false;这样做可能会解决此Q&A所涉及的僵局,并且还可以提高性能.
await和Wait()/ Result).当应用程序/服务启动时,它会正常运行一段时间,然后突然(几乎)所有传入的请求都会停止运行,它们永远不会产生响应.所有这些请求都在等待Redis完成呼叫的死锁.
有趣的是,一旦发生死锁,对Redis的任何调用都将挂起,但前提是这些调用是来自传入的API请求,这些调用是在线程池上运行的.
我们还从低优先级后台线程调用Redis,这些调用即使在发生死锁后也会继续运行.
似乎只有在线程池线程上调用Redis时才会出现死锁.我不再认为这是因为这些调用是在线程池线程上进行的.相反,似乎任何异步Redis调用没有延续,或者同步安全延续,即使在发生死锁情况后也会继续工作.(见下面我认为发生的事情)
混合引起的死锁await和Task.Result(像我们一样同步异步).但是我们的代码在没有同步上下文的情况下运行,因此这里不适用,对吧?
是的,我们不应该这样做.但我们这样做了,我们将不得不继续这样做一段时间.需要迁移到异步世界的大量代码.
同样,我们没有同步上下文,所以这不应该导致死锁,对吧?
ConfigureAwait(false)在任何设置之前设置await对此没有影响.
异步命令和Task.WhenAny等待StackExchange.Redis之后的超时异常
这是线程劫持问题.目前的情况如何?这可能是问题吗?
来自Marc的回答:
...混合等待和等待不是一个好主意.除了死锁之外,这是"同步异步" - 一种反模式.
但他也说:
SE.Redis在内部绕过sync-context(库代码正常),所以它不应该有死锁
因此,根据我的理解,StackExchange.Redis应该与我们是否使用同步异步 …
我StackExchange.Redis在我的Nancy应用程序中使用(SE.R).有一个全局ConnectionMultiplexer由Nancy TinyIoC通过构造函数参数自动传递,任何时候我尝试使用GetDatabase其中一个*Async方法(同步方法只在尝试了一个异步方法后才开始失败)我的应用程序死锁.
看看我的并行堆栈,看起来我有四个线程:
Result我的一个使用SE.R的任务的线程.(在堆栈上有很多Nancy东西,然后调用我的库使用SE.R,并调用Result.堆栈顶部是Monitor.Wait).Native to Managed Transition,ThreadHelper.ThreadStart在堆栈的顶部是ThreadHelper.ThreadStart_Context.Monitor.WaitMonitor.WaitSocketManager.WriteAllQueuesSocketManager.cctor.AnonymousMethod__16Managed to Native TransitionSocketManager.ReadImplSocketManager.ReadSocketManager.cctor.AnonymousMethod__19我几乎可以肯定这是某种僵局.我甚至认为这可能与这个问题有关.但我不知道该怎么做.
该ConnectionMultiplexer设置在南希IRegistrations用下面的代码:
var configOpts = new ConfigurationOptions {
EndPoints = {
RedisHost,
},
Password = RedisPass,
AllowAdmin = false,
ClientName = ApplicationName,
ConnectTimeout = 10000,
SyncTimeout = 5000,
};
var mux = …Run Code Online (Sandbox Code Playgroud)