sfa*_*ust 1 .net c# webclient task-parallel-library async-await
好了,所以我一直在阅读了大量和最好的方式工作使用async methods和task,等我相信我(主要)了解它,但我要检查,以确保.
我确实开始async wrappers使用同步任务,Task.Run()但最近读到,只有拥有一个sync method并让应用程序确定是否需要通过使用Task.Run()自身将其推送到另一个线程更好,这是有道理的.但是,我也读过这个例外是自然而然的async functions.我不知道我完全理解"自然异步",但作为一个基本的了解似乎.NET框架的方法,提供async methods的naturally async和WebClient.DownloadFile/DownlodFileAsync是其中之一.
所以我有两种方法,如果有人愿意提供反馈,我想测试我的理解,并确保这是正确的.
方法一是在本地操作系统上移动一些文件,看起来像这样(伪代码):
Public static void MoveStagingToCache()
{
...do some file move, copy, delete operations...
}
Run Code Online (Sandbox Code Playgroud)
第二个看起来像这样(伪代码):
Public static void DownloadToCache()
{
...do some analysis to get download locations...
using (var wc = new WebClient())
{
wc.DownloadFile(new Uri(content.Url), targetPath);
}
...do other stuff...
}
Run Code Online (Sandbox Code Playgroud)
所以我的理解如下.第一种方法应保持原样,因为没有文件操作方法具有async versions,因此不太可能async.调用者只需调用MoveStagingToCache()运行同步或调用Task.Run(()=>MoveStagingToCache())将其推送到后台线程即可.
但是,在第二种方法中,下载自然是async(除非我误解),因此它可以创建同步和异步版本.为了做到这一点,我不应该像这样包装同步方法:
Public static Task DownloadToCacheAsync()
{
return Task.Run(()=>DownloadToCache());
}
Run Code Online (Sandbox Code Playgroud)
相反,我应该使核心方法异步如下:
Public static async Task DownloadToCache()
{
...do some analysis to get download locations...
using (var wc = new WebClient())
{
await wc.DownloadFileTaskAsync(new Uri(content.Url), targetPath);
}
...do other stuff...
}
Run Code Online (Sandbox Code Playgroud)
然后我可以像这样创建同步版本:
Public static void DownloadToCache()
{
DownloadToCacheAsync().Wait();
}
Run Code Online (Sandbox Code Playgroud)
这允许使用自然异步方法,并且还为需要它的人提供同步过载.
这是对系统的一个很好的理解还是我弄乱了什么?
另外顺便说一句,在差异WebClient.DownloadFileAsync和WebClient.DownloadFileTaskAsync刚才说的任务返回错误捕获任务?
编辑
好吧,经过评论和答案的一些讨论,我意识到我应该在我的系统和预期用途上添加更多细节.这是一个打算在桌面上运行的库,而不是ASP.因此,我不关心为请求处理保存线程,主要关注的是保持UI线程打开并响应用户并将"后台"任务推送到另一个可由系统处理的线程他们正在做他们需要做的事情.
因为MoveStagingToCache,这将在程序启动时调用,但我不需要等待它完成继续加载或使用该程序.在大多数情况下,它将在程序的其余部分启动并运行之前完成,并让用户最有可能做任何事情(可能最多5-10秒运行时间),但即使在用户交互开始之前它没有完成,程序也能正常工作.因此,我的主要愿望是将此操作从UI线程移开,启动它,然后继续执行该程序.
所以对于这个,我目前的理解是这个方法应该在库中同步,但是当我从主(UI)线程调用它时我只是使用
Task.Run(()=>MoveStagingToCache());
Run Code Online (Sandbox Code Playgroud)
由于我在完成时并不需要做任何事情,我真的不需要等待这个吗?如果我只是执行上述操作,它将在后台线程上启动操作?
对于DownloadToCache,类似但有点不同.我希望用户能够启动下载操作,然后继续在UI中工作,直到下载完成.完成之后,我需要做一些简单的操作来通知用户它已经准备就绪并启用"使用它"按钮等.在这种情况下,我的理解是我会创建它作为异步方法等待WebClient下载电话.这会将其从实际下载的UI线程推出,但是一旦下载完成就会返回,以便在等待调用之后允许我做任何需要的UI更新.
正确?
你不应该写同步方法异步包装,但你也应该写为异步方法同步包装 -这些都反模式.
提示:"自然异步" 主要是指基于I/O的,只有少数例外.其中一个例外是一些文件系统操作,遗憾的是,包括移动文件,这些文件应该是异步的,但API不支持异步,因此我们必须假装它是同步的.
在你的情况下,DownloadToCache绝对是自然异步.在这些情况下,我更喜欢只暴露异步API .
如果你必须(或者真的想)支持同步API,我推荐使用boolean参数hack.语义是如果你传入sync:true,则返回的任务已经完成.这允许您将逻辑保存在单个方法中并编写非常小的包装器,而不会出现通常与这些包装器相关的陷阱:
private static async Task DownloadToCacheAsync(bool sync)
{
...do some analysis to get download locations...
using (var wc = new WebClient())
{
if (sync)
wc.DownloadFile(new Uri(content.Url), targetPath);
else
await wc.DownloadFileTaskAsync(new Uri(content.Url), targetPath);
}
...do other stuff...
}
public static Task DownloadToCacheAsync() => DownloadToTaskAsync(sync: false);
public static void DownloadToCache() => DownloadToTaskAsync(sync: true).GetAwaiter().GetResult();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
511 次 |
| 最近记录: |