C# 包装慢速同步I/O以实现异步UI使用

C# 包装慢速同步I/O以实现异步UI使用,c#,wpf,mvvm,async-await,task,C#,Wpf,Mvvm,Async Await,Task,我有一个外部库,它可以减慢I/O速度(串行+无线等),API中没有异步(甚至是老式的) 我正试图找到一种方法来包装它,以便从UI中轻松使用,这样我的用户就可以在不冻结整个UI的情况下进行连接,最好是让我可以async等待它 但我读到了一些相互矛盾的建议,比如“只使用Task.Run进行CPU限制的操作” 那么,我该怎么办?只需async waita任务。运行(省略ConfigurAwait(false)),或实现整个INotifyCompletion?区分“理想”和“现实世界”很重要。理想情况下

我有一个外部库,它可以减慢I/O速度(串行+无线等),API中没有异步(甚至是老式的)

我正试图找到一种方法来包装它,以便从UI中轻松使用,这样我的用户就可以在不冻结整个UI的情况下进行连接,最好是让我可以
async等待它

但我读到了一些相互矛盾的建议,比如“只使用Task.Run进行CPU限制的操作”


那么,我该怎么办?只需
async wait
a
任务。运行
(省略
ConfigurAwait(false)
),或实现整个
INotifyCompletion

区分“理想”和“现实世界”很重要。理想情况下,
async
应该一直都是。理想情况下,所有I/O都应该是异步的,并且不会耗尽线程池线程,
Task.Run
仅用于CPU绑定的方法。理想情况下,
async void
应仅用于事件处理程序

在现实世界中,有时由于缺少时间(或库支持),您必须混合使用
异步
和同步。在现实世界中,并非所有I/O操作都有异步API,甚至像
HttpClient
这样的全新类型也使用线程池线程来处理没有人愿意花时间修复的旧DNS解析代码。在现实世界中,
async void
有时比裸延续更干净,即使它不用于事件处理程序


在您的情况下,我只使用
任务。运行
而不必担心它。
Task.Run
的主要问题是当您在ASP.NET应用程序或库中使用它时,它可能会干扰线程池的其他使用。由于您正在处理UI应用程序,因此对I/O使用
Task.Run
并不“理想”,但作为一种折衷,这是一个非常好的选择。

我认为这取决于每个用例。我在处理串行提交时使用Thread对象,因为我想要侦听,而不仅仅是发送,或者您可以使用事件。但是执行http请求可以在Task.Run()中等待。这在某种程度上取决于你正在做的工作。粗略的谷歌搜索产生了多篇关于如何不使用
Task的文章。运行
进行非CPI绑定的操作,我还发现了一个来自微软的声明,说创建一个异步包装器到同步方法是一个坏主意idea@fstam没有任何理由仅仅因为你正在阅读IO而不是发送它就需要一个线程。但是应该明确的是,@MindSwipe链接的博客文章假设你能够修改库,例如,添加“真正的”异步方法。在我看来,如果您只是想取消UI线程的长时间运行调用,Task.Run()不是一个坏主意,即使对于I/O也是如此。至少您必须以某种方式处理这样一个事实,即API调用可能会阻止调用线程。@在串行情况下,您可能会遇到这种情况。dot net SerialPort类启动自己的线程,并通过事件通知使用者接收到的数据。谢谢。我将用注释“Stephen Cleary的赦免”提交我的代码: