首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >StackExchange.Redis死锁

StackExchange.Redis死锁
EN

Stack Overflow用户
提问于 2014-12-01 18:49:19
回答 1查看 3.8K关注 0票数 8

我在我的南希应用程序中使用StackExchange.Redis (SE.R从今以后)。只有一个全局ConnectionMultiplexer通过构造函数参数由南希的TinyIoC自动传递,每当我尝试使用GetDatabase和一个*Async方法(只有在尝试了一个异步方法之后才开始失败),我的应用程序就会死锁。

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

  1. 在我使用SE.R的任务上调用Result的线程(堆栈中有大量的Nancy,然后调用了使用SE.R的库,并调用了Result )。堆栈的顶部是Monitor.Wait)。
  2. 产生另外两个线程的线程。我假设这是由SE.R.管理的,从Native to Managed TransitionThreadHelper.ThreadStart开始,在堆栈的顶部是ThreadHelper.ThreadStart_Context
  3. 像这样卡住的一个小堆栈:
    • Monitor.Wait
    • Monitor.Wait
    • SocketManager.WriteAllQueues
    • SocketManager.cctor.AnonymousMethod__16

  1. 另一个看起来像这样的小堆栈:
    • Managed to Native Transition
    • SocketManager.ReadImpl
    • SocketManager.Read
    • SocketManager.cctor.AnonymousMethod__19

我几乎肯定这是某种僵局。我甚至认为这可能与this question有关。但我不知道该怎么办。

ConnectionMultiplexer是在南希IRegistrations中设置的,代码如下:

代码语言:javascript
复制
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。其中一小部分(包括抛出错误的代码)如下:

代码语言:javascript
复制
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();
        }
    });
}

我还有一个类,它在一个需要缓存中的一些信息的方法中使用这个方法:

代码语言:javascript
复制
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中失败(然后是一个关于没有可用连接的异常)。唯一的区别是,我通过依赖项注入获得了缓存的一个实例,而且我确信Nancy使用任务来并行化请求。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-12-01 22:03:12

我们开始:

代码语言:javascript
复制
return Cache.UseCache1().Result

砰;僵局但与StackExchange.Redis无关。

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

注意: StackExchange.Redis 不使用同步上下文;它显式地断开与同步上下文的连接,以避免导致死锁(这是正常的,推荐用于库)。关键是您的代码没有。

选项:

  • 不要把async.Result / .Wait()混在一起,或者
  • 让您所有的await调用(或者至少在.UseCache1()下面的调用)都显式地调用.ConfigureAwait(false) -注意,这意味着在调用上下文中不会发生完成!

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

这是一个非常常见的问题:I did pretty much the same thing

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27235124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档