Отмена задачи, которая получает URL-адреса асинхронно - PullRequest
7 голосов
/ 31 января 2012

У меня возникла небольшая проблема с поиском, как отменить эту задачу в C #. У меня нет четкого понимания работы с потоками, и я попробовал Googling для нескольких простых примеров кода, чтобы выручить меня, но я действительно не получил нигде Вот фрагмент кода, над которым я работаю:

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, заключается в том, что пользовательский интерфейс не блокируется во время загрузки URL-адресов.)

Если это немного сбивает с толку, вот краткое описание того, чего я пытался достичь с помощью своего кода:

  • У меня есть массив URL-адресов, я хочу загрузить каждый URL-адрес асинхронно, не блокируя пользовательский интерфейс.
  • Я бы предпочел, чтобы пользователь не давал программе загружать URL-адреса, нажимая кнопку, что в значительной степени отменяет цепочку.
  • Когда пользователь снова нажимает кнопку, программа снова загружает URL-адреса из этого массива.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 31 января 2012

Не знаю, является ли это правильным способом сделать это или нет, но я смог отменить задачи, используя следующий код.Я создал форму с ListBox и ProgressBar, поэтому я поднимаю и обрабатываю ProgressChanged событие BackgroundWorker.Надеюсь, это вам как-то поможет.

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;
}
1 голос
/ 31 января 2012

В WebClient вы можете использовать метод CancelAsync , чтобы отменить асинхронную операцию.

Чтобы отменить задачи, которые вы запускаете с помощью Factory.StartNew, вы должны использовать CancellationTokenSource . Вам нужно передать CancellationTokenSource.Token задачам (и вы можете спросить, отменен ли токен уже с помощью token.IsCancellationRequested), и вам нужно позвонить CancellationTokenSource.Cancel(), чтобы установить токен как отмененный.

...