使用TPL / C#5 / .NET 4.0进行非阻塞等待

时间:2016-01-12 17:24:14

标签: c# async-await task-parallel-library nonblocking

我有一些常见的代码需要重构回C#5(我原来的问题说C#4)/ .NET 4.0,这样我就可以在更多的项目中分享它。最大的影响是没有使用async / await并切换回TPL并使用ContinueWith()

有没有办法在同步对象上完成非阻塞等待而不通过将其放入后台线程来模拟它?定时器我可以使用TaskCompletionSource,所以我很高兴。

SemaphoreSlim mutex = new SemaphoreSlim(1);

await mutex.WaitAsync(); // <-- how to get a Task that completes on mutex.Wait()

e.g。

mutex.WaitInATask().ContinueWith(...

更新我决定不针对C#4.0(但仍然针对.NET 4.0框架),因为我更关心程序集而不是源代码可以在项目之间共享

我决定使用Microsoft.Bcl.Async,Stephen Cleary的AsyncEx,目标.NET 4.0框架,并将build C#版本设置为5.0(支持async / await)。这可能需要VS2015进行编译,但程序集(以及依赖项)将以.NET 4.0为目标。

此路线的额外好处是从async / awaitContinueWith()重构的代码较少,这样可以减少错误...

1 个答案:

答案 0 :(得分:0)

通过对该问题的评论启发的研究,我得出了以下答案:

首先,我将编译器的要求降低为C#4.0。这意味着二进制文件仍将与.NET 4.0 Framework兼容,但源代码将需要支持C#5.0的编译器(例如Visual Studio 2015)。我可以与遗留项目共享二进制文件,但不能共享源代码。

在.NET 4.0 Framework中进行非阻塞等待的最简单方法是:

  1. 创建一个面向.NET 4.0 Framework的类库项目(使用新项目执行此操作以避免在创建后切换框架版本时引用无法正确更新)

  2. 将C#版本(在VS 2015中,项目属性/构建/高级)设置为5.0。这启用了async / await语法,这意味着我不需要将所有异步/等待重新编码为丑陋,复杂的.ContinueWith()嵌套和黑客。

  3. 添加NuGet包Nito.AsyncEx和Microsoft.Bcl.Async(后者附带前者,但我发现我需要包含比Nito所需的更新版本的Microsoft.Bcl.Async。 .AsyncEx,所以我先添加了Microsoft.Bcl.Async。

  4. 使用WaitAsync()转换任何同步对象以使用AsyncEx版本,例如: SemaphoreSlim =&gt; AsyncSemaphore。

  5. 至少,这允许我通过引用我们旧的.NET 4.0项目中的二进制文件来重用一些有价值的功能,这些项目目前无法升级。