取消异步检索URL的任务

本文关键字:任务 URL 检索 异步 取消 | 更新日期: 2023-09-27 18:21:52

我在C#中发现如何取消此任务有点问题。我对处理线程并没有很强的理解,我试着在谷歌上搜索一些简单的代码示例来帮助我,但我真的不知道在哪里。这是我正在处理的一段代码:

var tasks = urls.Select(url => Task.Factory.StartNew(
state =>
{
    using (var client = new WebClient())
    {
        lock (this)
        {
        // code to download stuff from URL
        }
    }
}, url)).ToArray();
    try
    {
       Task.WaitAll(tasks);
    }
    catch (Exception e)
    {
      textBox2.AppendText("Error: " + e.ToString());
    }

其中"urls"是一个URL数组。有没有一种简单的方法,当我点击程序中的一个按钮时,URL的下载就会完全停止?此外,我粘贴的代码片段位于backgroundWorker1调用的一个函数中,我认为这可能会使事情变得更加复杂。(我之所以有backgroundWorker,是因为UI在下载URL时不会锁定。)

如果这有点令人困惑的话,下面是我试图用我的代码实现的目标:

  • 我有一个URL数组,我想异步下载每个URL,而不锁定UI
  • 我更希望用户通过点击一个按钮来阻止程序下载URL,这相当于取消了线程
  • 当用户再次单击按钮时,程序将再次从该数组中下载URL

提前谢谢。

取消异步检索URL的任务

不知道这是否是正确的方法,但我已经能够使用以下代码取消任务。我已经用ListBoxProgressBar创建了一个表单,所以我正在引发和处理BackgroundWorkerProgressChanged事件。希望这对你有所帮助。

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    CancellationTokenSource _tokenSource = new CancellationTokenSource();
    CancellationToken _token = _tokenSource.Token;
    var urls = e.Argument as IEnumerable<string>;
    _token = new CancellationToken();
    if (urls == null) return;
    var i = 0;
    var a = 100 / urls.Count();
    var sb = new StringBuilder();
    var t = urls.Select(url => Task.Factory.StartNew(
                    (u) =>{
                        using (var wc = new WebClient())
                        {
                            lock (this){
                                var s = wc.DownloadString(u.ToString());
                                sb.AppendFormat("{1}:{0}'r'n", "", u);
                            }
                        }
                    if (Worker.CancellationPending){
                        //MAGIC HAPPENS HERE, IF BackgroundWorker IS REQUESTED
                        //TO CANCEL, WE CANCEL CancellationTokenSource
                        _tokenSource.Cancel();
                    }
                    //IF CANCELATION REQUESTED VIA CancellationTokenSource
                    //THROW EXCEPTION WHICH WILL ADD TO AggreegateException
                    _token.ThrowIfCancellationRequested();
                    //YOU CAN IGNORE FOLLOWING 2 LINES
                    i += a;
                    Worker.ReportProgress(i, u);
    }, url, _token)).ToArray();
    try
    {
        Task.WaitAll(t);
    }
    catch (AggregateException age)
    {
        if (age.InnerException is OperationCanceledException)
            sb.Append("Task canceled");
    }
    catch (Exception ex)
    {
        sb.Append(ex.Message);
    }
    e.Result = sb;
}

使用WebClient,可以使用CancelAsync方法取消异步操作。

要取消您通过Factory.StartNew启动的任务,您应该使用CancellationTokenSource。您需要将CancellationTokenSource.Token传递给任务(您可以询问是否已经使用token.IsCancellationRequested取消了令牌),然后调用CancellationTokenSource.Cancel()将令牌设置为已取消。