使用 TPL / C# 5 / .NET 4.0 的非阻塞等待
Non-blocking waits using TPL / C# 5 / .NET 4.0
我有一些通用代码需要重构回 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()
例如
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 中让 non-blocking 等待的最干净的方法是:
创建一个以 .NET 4.0 Framework 为目标的 Class 库项目(使用新项目执行此操作以避免在创建后切换框架版本时引用未正确更新)
将 C# 版本(在 VS 2015 中,项目属性/生成/高级)设置为 5.0。这启用了 async/await 语法,这意味着我不需要 re-code 我所有的 async/await 进入丑陋、复杂的 .ContinueWith() 嵌套和 hacks。
添加 NuGet 包 Nito.AsyncEx 和 Microsoft.Bcl.Async(后者随前者一起提供,但我发现我需要包含比之前更新的 Microsoft.Bcl.Async 版本Nito.AsyncEx 要求作为依赖项,所以我首先添加了 Microsoft.Bcl.Async)。
使用 WaitAsync() 将任何同步对象转换为使用 AsyncEx 版本,例如SemaphoreSlim => AsyncSemaphore.
至少,这允许我通过引用我们较旧的 .NET 4.0 项目中的二进制文件来 re-use 一些有价值的功能,这些项目目前由于各种原因无法升级。
我有一些通用代码需要重构回 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()
例如
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 中让 non-blocking 等待的最干净的方法是:
创建一个以 .NET 4.0 Framework 为目标的 Class 库项目(使用新项目执行此操作以避免在创建后切换框架版本时引用未正确更新)
将 C# 版本(在 VS 2015 中,项目属性/生成/高级)设置为 5.0。这启用了 async/await 语法,这意味着我不需要 re-code 我所有的 async/await 进入丑陋、复杂的 .ContinueWith() 嵌套和 hacks。
添加 NuGet 包 Nito.AsyncEx 和 Microsoft.Bcl.Async(后者随前者一起提供,但我发现我需要包含比之前更新的 Microsoft.Bcl.Async 版本Nito.AsyncEx 要求作为依赖项,所以我首先添加了 Microsoft.Bcl.Async)。
使用 WaitAsync() 将任何同步对象转换为使用 AsyncEx 版本,例如SemaphoreSlim => AsyncSemaphore.
至少,这允许我通过引用我们较旧的 .NET 4.0 项目中的二进制文件来 re-use 一些有价值的功能,这些项目目前由于各种原因无法升级。