【问题标题】:C# Cancel Task with started List<>C# 使用已启动的 List<> 取消任务
【发布时间】:2016-12-30 18:19:46
【问题描述】:

我从列表开始任务并等待 Task.WhenAll

private async void btn_download_Click(object sender, EventArgs e)
    {
        .
        .
        .
        await DownloadMultipleFilesAsync(old_json);
        Console.WriteLine("Download completed.");
    }

这是我用列表开始任务的代码。

private async Task DownloadMultipleFilesAsync(List<media> doclist)
    {
        var token = cancelTokenSource.Token;
        await Task.WhenAll(doclist.Select(doc => DownloadFileAsync(doc)));
        btn_download.Enabled = true;
    }

还有我的下载方法

private async Task DownloadFileAsync(media media)
{
    .
    .
    .
    Console.WriteLine(media.no + media_ext + " started.");
    webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
    await webClient.DownloadFileTaskAsync(new Uri(media.url), @downloadToDirectory);
    Console.WriteLine(media.no + media_ext + " finished.");
    .
    .
    .
}

输出窗口如下:

1.jpg started.
2.jpg started.
3.jpg started.
4.jpg started.
5.jpg started.
6.jpg started.
7.jpg started.
8.jpg started.
9.jpg started.
10.jpg started.
11.jpg started.
12.jpg started.
13.jpg started.
14.jpg started.
15.jpg started.
16.jpg started.
17.jpg started.
18.jpg started.
19.jpg started.
1.jpg finished.
4.jpg finished.
2.jpg finished.
6.jpg finished.
8.jpg finished.
10.jpg finished.
3.jpg finished.
5.jpg finished.
12.jpg finished.
14.jpg finished.
7.jpg finished.
16.jpg finished.
18.jpg finished.
9.jpg finished.
11.jpg finished.
13.jpg finished.
15.jpg finished.
17.jpg finished.
19.jpg finished.
Download completed.

我想点击 btn_cancel 并取消启动任务并等待完成启动任务。

private void btn_cancel_Click(object sender, EventArgs e)
{
    cancelTokenSource.Cancel();
    cancelTokenSource = new CancellationTokenSource();
}

【问题讨论】:

  • 你的问题是什么?
  • 使用Task.WaitAll(doclist.Select(doc =&gt; DownloadFileAsync(doc)).ToArray(), token)
  • @MatiasCicero 我不能那样使用prntscr.com/c9iiql
  • @SonerB 你没有在Select之后调用ToArray() ...
  • @MatiasCicero 现在我试试。下载开始并在完成时冻结程序。

标签: c# asynchronous multitasking cancellationtokensource cancellation-token


【解决方案1】:

您需要做的是将取消令牌传递到调用链中,然后在可能的情况下使用它,您还需要注册一个取消回调以调用WebClient.CancelAsync() 以取消下载。

private async void btn_download_Click(object sender, EventArgs e)
{
    .
    .
    .
    var token = cancelTokenSource.Token;
    try
    {
        await DownloadMultipleFilesAsync(old_json, token);
        Console.WriteLine("Download completed.");
    }
    catch(OperationCanceledException ex)
    {
        //If something other than our token caused the cancel bubble up the exception.
        if(ex.CancellationToken != token)
            throw;
    }
}


private async Task DownloadMultipleFilesAsync(List<media> doclist, CancellationToken token)
{
    await Task.WhenAll(doclist.Select(doc => DownloadFileAsync(doc, token));
    btn_download.Enabled = true;
}


private async Task DownloadFileAsync(media media, CancellationToken token)
{
    .
    .
    .
    Console.WriteLine(media.no + media_ext + " started.");
    webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
    try
    {
        using(token.Register(() => webClient.CancelAsync()))
        {
            await webClient.DownloadFileTaskAsync(new Uri(media.url), @downloadToDirectory);
        }
    }            
    catch (WebException ex)
    {
        //Raise a OperationCanceledException if the request was canceled, otherwise bubble up the exception.
        if(ex.Status == WebExceptionStatus.RequestCanceled)
            throw new OperationCanceledException(token);
        else
            throw;
    }
    Console.WriteLine(media.no + media_ext + " finished.");
    .
    .
    .
}

【讨论】:

  • 非常感谢。我尝试并工作。但是输出窗口是这样的:prntscr.com/c9j0pg
  • 您可能没有打开"Just My Code",或者您在btn_download_Click catch 块中做错了什么,导致异常通过。
【解决方案2】:

WebClient 不接受 CancelationToken,这很奇怪。相反,它有一个方法CancelAsync,您可以调用它来取消挂起的调用。

似乎您必须保留您的 webClient 引用,并在单击取消按钮时调用该方法。

【讨论】:

  • 您不需要保留它,只需使用CancellationToken.Register 并从委托内部调用函数,只需将令牌传递到链中的函数即可。
  • @ScottChamberlain,绝对不错。以前没用过那个。那肯定会抽象出实现细节。
  • 我很抱歉。我正在学习 C#,但我不知道如何插入 CancellationToken.Register 我的方法。你能解释一下或者举个例子吗?
  • @SonerB 看看我发布的答案,我告诉你如何改变所有的方法来做到这一点。
  • @SonerB Scott 给了你一个完整的答案。我会使用他的并将其标记为已接受的答案
猜你喜欢
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
相关资源
最近更新 更多