相关疑难解决方法(0)

如何防止Task上的同步延续?

我有一些库(套接字网络)代码,它Task基于提供基于API的待处理请求响应TaskCompletionSource<T>.然而,TPL中的一个烦恼是,似乎不可能阻止同步延续.我会希望能够做的是两种:

  • 告诉a 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)

.net c# task task-parallel-library async-await

80
推荐指数
2
解决办法
7931
查看次数

访问StackExchange.Redis时出现死锁

我在调用StackExchange.Redis时遇到了死锁情况.

我不确切知道发生了什么,这是非常令人沮丧的,我希望任何有助于解决或解决此问题的输入.


万一你也有这个问题,不想读这一切; 我建议你将尝试设置PreserveAsyncOrderfalse.

ConnectionMultiplexer connection = ...;
connection.PreserveAsyncOrder = false;
Run Code Online (Sandbox Code Playgroud)

这样做可能会解决此Q&A所涉及的僵局,并且还可以提高性能.


我们的设置

  • 代码作为控制台应用程序或Azure辅助角色运行.
  • 它使用HttpMessageHandler公开REST api,因此入口点是异步的.
  • 代码的某些部分具有线程关联(由单个线程拥有,并且必须由单个线程运行).
  • 代码的某些部分仅为异步.
  • 我们正在进行异步同步异步同步反模式.(混合awaitWait()/ Result).
  • 我们在访问Redis时只使用异步方法.
  • 我们使用StackExchange.Redis 1.0.450 for .NET 4.5.

僵局

当应用程序/服务启动时,它会正常运行一段时间,然后突然(几乎)所有传入的请求都会停止运行,它们永远不会产生响应.所有这些请求都在等待Redis完成呼叫的死锁.

有趣的是,一旦发生死锁,对Redis的任何调用都将挂起,但前提是这些调用是来自传入的API请求,这些调用是在线程池上运行的.

我们还从低优先级后台线程调用Redis,这些调用即使在发生死锁后也会继续运行.

似乎只有在线程池线程上调用Redis时才会出现死锁.我不再认为这是因为这些调用是在线程池线程上进行的.相反,似乎任何异步Redis调用没有延续,或者同步安全延续,即使在发生死锁情况后也会继续工作.(见下面我认为发生的事情)

有关

  • StackExchange.Redis死锁

    混合引起的死锁awaitTask.Result(像我们一样同步异步).但是我们的代码在没有同步上下文的情况下运行,因此这里不适用,对吧?

  • 如何安全地混合同步和异步代码?

    是的,我们不应该这样做.但我们这样做了,我们将不得不继续这样做一段时间.需要迁移到异步世界的大量代码.

    同样,我们没有同步上下文,所以这不应该导致死锁,对吧?

    ConfigureAwait(false)在任何设置之前设置await对此没有影响.

  • 异步命令和Task.WhenAny等待StackExchange.Redis之后的超时异常

    这是线程劫持问题.目前的情况如何?这可能是问题吗?

  • StackExchange.Redis异步调用挂起

    来自Marc的回答:

    ...混合等待和等待不是一个好主意.除了死锁之外,这是"同步异步" - 一种反模式.

    但他也说:

    SE.Redis在内部绕过sync-context(库代码正常),所以它不应该有死锁

    因此,根据我的理解,StackExchange.Redis应该与我们是否使用同步异步 …

c# deadlock asynchronous stackexchange.redis

72
推荐指数
1
解决办法
8005
查看次数

StackExchange.Redis死锁

StackExchange.Redis在我的Nancy应用程序中使用(SE.R).有一个全局ConnectionMultiplexer由Nancy TinyIoC通过构造函数参数自动传递,任何时候我尝试使用GetDatabase其中一个*Async方法(同步方法只在尝试了一个异步方法后才开始失败)我的应用程序死锁.

看看我的并行堆栈,看起来我有四个线程:

  1. 调用Result我的一个使用SE.R的任务的线程.(在堆栈上有很多Nancy东西,然后调用我的库使用SE.R,并调用Result.堆栈顶部是Monitor.Wait).
  2. 一个产生两个其他线程的线程.我认为这是由SE.R管理的.从堆栈开始Native to Managed Transition,ThreadHelper.ThreadStart在堆栈的顶部是ThreadHelper.ThreadStart_Context.
  3. 一个像这样粘在一起的小堆栈:
    • Monitor.Wait
    • Monitor.Wait
    • SocketManager.WriteAllQueues
    • SocketManager.cctor.AnonymousMethod__16
  4. 另一个小堆栈看起来像这样:
    • Managed to Native Transition
    • SocketManager.ReadImpl
    • SocketManager.Read
    • SocketManager.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)

task-parallel-library async-await stackexchange.redis

7
推荐指数
1
解决办法
2561
查看次数