使用TPL/C#5/.NET 4.0进行非阻塞等待
本文关键字:等待 TPL C#5 NET 使用 | 更新日期: 2023-09-27 18:29:56
我有一些常用代码需要重构回C#5(我最初的问题是C#4)/.NET4.0,这样我就可以在更多的项目中共享它。最大的影响是不使用async
/await
并切换回TPL并使用ContinueWith()
。
有没有一种方法可以在同步对象上实现无阻塞等待,而无需将其放入后台线程中进行模拟?计时器我可以使用TaskCompletionSource
,所以我在那里很好。
SemaphoreSlim mutex = new SemaphoreSlim(1);
await mutex.WaitAsync(); // <-- how to get a Task that completes on mutex.Wait()
例如
mutex.WaitInATask().ContinueWith(...
UPDATE我决定不以C#4.0为目标(但仍然以.NET 4.0框架为目标),因为我更关心程序集,而不是能够在项目之间共享的源代码。
我决定使用Microsoft.Bcl.Async,Stephen Cleary的AsyncEx,目标.NET 4.0框架,并将构建C#版本设置为5.0(以支持Async/await)。这可能需要VS2015进行编译,但程序集(以及依赖项)将以.NET 4.0为目标。
这种方法的额外好处是减少了从async
/await
到ContinueWith()
的重构代码,这将减少一路上的错误。。。
通过受问题评论启发的研究,我得出了以下答案:
首先,我放弃了编译器为C#4.0的要求。这意味着二进制文件仍将与.NET 4.0 Framework兼容,但源代码将需要支持C#5.0的编译器(例如Visual Studio 2015)。我可以与遗留项目共享二进制文件,但不能共享源代码。
在.NET 4.0 Framework中进行非阻塞等待的最干净的方法是:
-
创建一个以.NET 4.0 Framework为目标的类库项目(使用新项目执行此操作,以避免在创建后切换框架版本时引用无法正确更新)
-
将C#版本(在VS 2015中,项目属性/内部版本/高级)设置为5.0。这启用了async/await语法,这意味着我不需要将所有的async/await重新编码成丑陋、复杂的.ContineWith()嵌套和破解。
-
添加NuGet包Nito.AncEx和Microsoft.Bcl.Async(后者与前者一起提供,但我发现我需要包含比Nito.AsyncEx作为依赖项所需的更新版本的Microsoft.Bcl.异步,所以我首先添加了Microsoft.Bcl.sync)。
-
使用WaitAsync()转换任何同步对象以使用AsyncEx版本,例如SemaphoreSlim=>AsyncSemaphore。
至少,这允许我通过引用旧.NET 4.0项目中的二进制文件来重用一些有价值的功能,这些项目目前由于各种原因无法升级。