连续的任务

本文关键字:任务 连续 | 更新日期: 2023-09-27 18:19:17

我正试图找出如何正确地将任务链在一起。到目前为止,我有以下内容:

Task taskExe = new Task(() => startDownload(downloadLink, saveTo));
Task taskVersionTxt = taskExe.ContinueWith((t) => startDownload(versionLink, versionSaveTo));
Task taskWriteVersion = taskVersionTxt.ContinueWith((t) => writeNewVersion());
taskExe.Start();

这并不像我想象的那样工作,因为writenNewVersion需要完成前两个任务,以便它可以修改下载的文件。

这里是startDownload

private async Task startDownload(string link, string savePath)
{                              
    WebClient client = new WebClient();
    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);                    
}

将等待前一个任务完成的3个任务连接在一起的正确方法是什么?

连续的任务

startDownload已经异步。在一个新线程中启动它就是创建一个任务,这个任务的唯一任务就是启动一个新任务。如果您查看变量的实际类型,您会更清楚地看到这一点:

它们的实际类型是:

Task<Task> taskExe = new Task(() => 
    startDownload(downloadLink, saveTo));
Task<Task> taskVersionTxt = taskExe.ContinueWith((t) => 
    startDownload(versionLink, versionSaveTo));
Task<Task> taskWriteVersion = taskVersionTxt.ContinueWith((t) => 
    writeNewVersion());

当您完成异步操作时,您的任务完成,而不是当这些操作实际完成时。您需要通过Unwrap来等待包装的任务完成,而不是外部任务。或者,就此而言,从一开始就不要不必要地包装任务。

Task taskExe = startDownload(downloadLink, saveTo);
Task taskVersionTxt = taskExe.ContinueWith((t) => 
    startDownload(versionLink, versionSaveTo))
    .Unwrap();
Task taskWriteVersion = taskVersionTxt.ContinueWith((t) => 
    writeNewVersion())
    .Unwrap();

当然,使用await更简单:

await startDownload(downloadLink, saveTo);
await startDownload(versionLink, versionSaveTo);
await writeNewVersion();

如果您能够使用async/await,则该过程非常简单。启动前两个操作并行运行,然后使用await Task.WhenAll(...)等待它们都完成。

public async Task RunOperationAsync()
{
    List<Task> downloads = new List<Task>();
    downloads.Add(startDownload(downloadLink, saveTo));
    downloads.Add(startDownload(versionLink, versionSaveTo));
    await Task.WhenAll(downloads);
    await writeNewVersion();
}

问题是您同时使用任务和异步。如果您将startDownload方法中的async去掉,它应该可以工作,或者如果您停止使用任务。你以两种不同的方式使它异步,然后只同步其中一种,并期望它是同步的。

在LINQPad中,这按预期工作:

void Main()
{
    string downloadLink = "dl", saveTo = "st", versionLink = "vl", versionSaveTo = "vst";
    Task taskExe = new Task(() => startDownload(downloadLink, saveTo));
    Task taskVersionTxt = taskExe.ContinueWith((t) => startDownload(versionLink, versionSaveTo));
    Task taskWriteVersion = taskVersionTxt.ContinueWith((t) => writeNewVersion());
    taskExe.Start();
}
void startDownload(string dl, string st)
{
    Thread.Sleep(1000);
    ("Download done: " + dl + " " + st).Dump();
}
void writeNewVersion()    
{
    "Version done".Dump();
}
public async Task RunOperationAsync()
{
    await Task.WhenAll(
        startDownload(downloadLink, saveTo),
        startDownload(versionLink, versionSaveTo));
    await writeNewVersion();
}