gpt4 book ai didi

task-parallel-library - StackExchange.Redis 死锁

转载 作者:行者123 更新时间:2023-12-04 10:24:46 27 4
gpt4 key购买 nike

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

查看我的并行堆栈,我似乎有四个线程:

  • 调用 Result 的线程在我的一项使用 SE.R. 的任务上。 (堆栈上有很多 Nancy 的东西,然后调用我使用 SE.R 的库,并调用 Result 。堆栈顶部是 Monitor.Wait )。
  • 产生另外两个线程的线程。我认为这是由 SE.R. 管理的。以 Native to Managed Transition 开头, ThreadHelper.ThreadStart ,并且在堆栈的顶部是ThreadHelper.ThreadStart_Context .
  • 像这样卡住的小堆栈:
  • Monitor.Wait
  • Monitor.Wait
  • SocketManager.WriteAllQueues
  • SocketManager.cctor.AnonymousMethod__16
  • 另一个看起来像这样的小堆栈:
  • Managed to Native Transition
  • SocketManager.ReadImpl
  • SocketManager.Read
  • SocketManager.cctor.AnonymousMethod__19

  • 我几乎可以肯定这是某种僵局。我什至认为这可能与 this question 有关.但我不知道该怎么办。
    ConnectionMultiplexer设置在南希 IRegistrations使用以下代码:
    var configOpts =  new ConfigurationOptions {
    EndPoints = {
    RedisHost,
    },
    Password = RedisPass,
    AllowAdmin = false,
    ClientName = ApplicationName,
    ConnectTimeout = 10000,
    SyncTimeout = 5000,
    };
    var mux = ConnectionMultiplexer.Connect(configOpts);
    yield return new InstanceRegistration(typeof (ConnectionMultiplexer), mux);
    mux是由在其构造函数参数列表中请求它的所有代码共享的实例。

    我有一门课叫 SchemaCache .其中一小部分(包括引发相关错误的代码)如下:
    public SchemaCache(ConnectionMultiplexer connectionMultiplexer) {
    ConnectionMultiplexer = connectionMultiplexer;
    }

    private ConnectionMultiplexer ConnectionMultiplexer { get; set; }

    private async Task<string[]> Cached(string key, bool forceFetch, Func<string[]> fetch) {
    var db = ConnectionMultiplexer.GetDatabase();

    return forceFetch || !await db.KeyExistsAsync(key)
    ? await CacheSetSet(db, key, await Task.Run(fetch))
    : await CacheGetSet(db, key);
    }

    private static async Task<string[]> CacheSetSet(IDatabaseAsync db, string key, string[] values) {
    await db.KeyDeleteAsync(key);
    await db.SetAddAsync(key, EmptyCacheSentinel);

    var keysSaved = values
    .Append(EmptyCacheSentinel)
    .Select(val => db.SetAddAsync(key, val))
    .ToArray()
    .Append(db.KeyExpireAsync(key, TimeSpan.FromDays(1)));
    await Task.WhenAll(keysSaved);

    return values;
    }

    private static async Task<string[]> CacheGetSet(IDatabaseAsync db, string key) {
    var results = await db.SetMembersAsync(key);
    return results.Select(rv => (string) rv).Without(EmptyCacheSentinel).ToArray();
    }

    // There are a bunch of these public methods:
    public async Task<IEnumerable<string>> UseCache1(bool forceFetch = false) {
    return await Cached("the_key_i_want", forceFetch, () => {
    using (var cnn = MakeConnectionToDatabase("server", "databaseName")) {
    // Uses Dapper:
    return cnn.Query<string>("--expensive sql query").ToArray();
    }
    });
    }

    我还有一个类在需要缓存中的一些信息的方法中使用它:
    public OtherClass(SchemaCache cache) {
    Cache = cache;
    }

    private SchemaCache Cache { get; set; }

    public Result GetResult(Parameter parameter) {
    return Cache.UseCache1().Result
    .Where(r => Cache.UseCache2(r).Result.Contains(parameter))
    .Select(r => CheckResult(r))
    .FirstOrDefault(x => x != null);
    }

    以上所有方法在 LinqPad 中都可以正常工作,其中所有问题都只有一个实例。相反,它以 TimeoutException 失败。 (以及后来关于没有可用连接的异常(exception))。唯一的区别是我通过依赖注入(inject)获得了一个缓存实例,而且我很确定 Nancy 使用 Tasks 来并行化请求。

    最佳答案

    开始了:

    return Cache.UseCache1().Result

    繁荣;僵局。但与 StackExchange.Redis 无关。

    至少,来自大多数同步上下文提供者。这是因为您的 await s 都隐式请求同步上下文激活 - 这可能意味着“在 UI 线程上”(winforms、WPF)或“在当前指定的工作线程上”(WCF、ASP.NET、MVC 等)。这里的问题是 此线程将永远无法处理这些项目 , 因为 .Result是一个同步和阻塞调用。因此,您的任何完成回调都不会被处理,因为唯一可能处理它们的线程正在等待它们完成,然后才能使自己可用。

    注意:StackExchange.Redis 使用同步上下文;它显式断开与同步上下文的连接以避免成为死锁的原因(这是正常的,建议用于库)。关键是您的代码没有。

    选项:
  • 不要混合async.Result/.Wait() , 或
  • 拥有你所有的await调用(或至少在 .UseCache1() 下的调用)显式调用 .ConfigureAwait(false) - 但是请注意,这意味着完成不会发生在调用上下文中!

  • 第一个选项是最简单的;如果您可以隔离不依赖于同步上下文的调用树,那么第二种方法是可行的。

    这是一个非常普遍的问题; I did pretty much the same thing .

    关于task-parallel-library - StackExchange.Redis 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27235124/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com