【问题标题】:Nito.AsyncEx.AsyncLock stack overflow with lots of awaiters and synchronous fast pathNito.AsyncEx.AsyncLock 堆栈溢出,带有大量等待者和同步快速路径
【发布时间】:2016-09-30 05:03:51
【问题描述】:

我正在使用 Stephen Cleary 的 Nito.AsyncEx NuGet 包 (v3.0.1) 中的 AsyncLock 来保护昂贵资源的初始化,因此只有第一个调用者会执行耗时的异步初始化,所有后续调用者将异步等待,直到初始化完成,然后获取缓存的资源。

我首先注意到的是,受 AsyncLock 保护的区域之后的代码在任务中以 exact 任务启动的相反顺序执行(即最后一个任务开始到首先继续通过锁定区域,然后是倒数第二个任务,依此类推,直到第一个任务最后继续)。

然后在调查为什么会发生这种情况的过程中,我发现当有大量异步任务时,我总是会遇到堆栈溢出。这是一个简化的示例:

object _foo;
readonly Nito.AsyncEx.AsyncLock _fooLock = new Nito.AsyncEx.AsyncLock();

async Task<object> GetFooAsync()
{
    using (await _fooLock.LockAsync().ConfigureAwait(false))
    {
        if (_foo == null)
        {
            // Simulate time-consuming asynchronous initialization,
            // during which all the subsequent tasks end up awaiting the AsyncLock.
            await Task.Delay(5000).ConfigureAwait(false);
            _foo = new object();
        }
        return _foo;
    }
}

async Task DoStuffAsync()
{
    object foo = await GetFooAsync().ConfigureAwait(false);
    // Do stuff with foo...
}

void DoStuff()
{
    var tasks = new List<Task>();

    for (int i = 1; i <= 1000; i++)
    {
        tasks.Add(DoStuffAsync());
    }

    Task.WhenAll(tasks).Wait();
}

如果通过GetFooAsync() 的快速路径不是同步的(例如,如果我在return _foo; 之前添加await Task.Yield();),那么不仅不会发生堆栈溢出,而且任务会按照它们的顺序继续通过锁定区域开始于。

我可能会更改我的代码以使用 AsyncEx 中的 AsyncLazy&lt;T&gt; 来代替这个用例,我已经测试过并且似乎没有出现这个问题。

但是,我想知道这个问题是由于我的代码中的错误、AsyncLock 中的错误,还是只是预期的行为(更多的问题)?

【问题讨论】:

    标签: c# asynchronous async-await .net-4.5


    【解决方案1】:

    这是一个bug in AsyncLock;所有基于队列的异步协调原语都有同样的问题。修复工作正在进行中。

    new version of this library 有一个不存在此问题的重写队列。

    【讨论】:

    • 感谢您的快速回答!知道什么时候可以修复吗?或者可以做些什么来帮助解决这个问题?我很想使用新版本,但运行代码的系统目前卡在 .NET 4.5 上,而新版本似乎需要 .NET 4.6。
    • 延迟只是由于缺少支持低级平台(如 WP7.1 和 SL4)的构建机器。我决定只针对较新的问题进行构建,所以这将是4.x 版本。希望这个周末在某个时候。新版本确实需要 net46 - 新的异步队列需要它。
    猜你喜欢
    • 2018-09-09
    • 2015-08-05
    • 2010-10-30
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 2018-07-09
    相关资源
    最近更新 更多