2012-01-31 48 views
7

Tôi đang gặp sự cố khi tìm hiểu cách hủy tác vụ này trong C#. Tôi không chính xác có một sự hiểu biết mạnh mẽ về xử lý các chủ đề và tôi đã cố gắng Googling cho một số ví dụ mã đơn giản để giúp tôi ra nhưng tôi đã nhận được thực sự không có nơi. Đây là đoạn mã tôi đang làm việc:Hủy tác vụ truy xuất URL không đồng bộ

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()); 
    } 

Trong đó "url" là một mảng URL. Có một cách đơn giản để làm cho nó để, khi tôi nhấp vào một nút trong chương trình của tôi, việc tải xuống các URL được dừng lại hoàn toàn? Ngoài ra, đoạn mã tôi đã dán nằm trong một hàm mà các cuộc gọi backgroundWorker1, mà tôi cho rằng có thể làm cho mọi thứ trở nên phức tạp hơn một chút. (Lý do tại sao tôi có một backgroundWorker là như vậy giao diện người dùng không bị khóa trong khi nó đang tải xuống các URL.)

Nếu có bất kỳ cách nào gây nhầm lẫn, đây là một phác thảo về những gì tôi đã cố gắng đạt được với mã:

  • Tôi có một loạt URL, tôi muốn tải xuống mọi URL không đồng bộ mà không cần khóa giao diện người dùng.
  • Tôi muốn người dùng dừng chương trình tải xuống URL bằng cách nhấp vào nút, khá nhiều khi hủy chuỗi.
  • Khi người dùng nhấp vào nút một lần nữa, chương trình sẽ tải lại tất cả các URL từ mảng đó.

Xin cảm ơn trước.

+0

Vui lòng không bao gồm các thẻ trong tiêu đề câu hỏi của bạn; nó chỉ làm việc nhiều hơn cho những người trong chúng ta quan tâm đến tính nhất quán trên SO. –

Trả lời

1

Không biết đây có phải là cách phù hợp để thực hiện việc này hay không, nhưng tôi đã có thể hủy tác vụ bằng cách sử dụng mã sau. Tôi đã tạo biểu mẫu với ListBoxProgressBar vì vậy tôi đang tăng và xử lý sự kiện ProgressChanged của BackgroundWorker. Hy vọng điều này sẽ giúp bạn trong một số cách.

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; 
} 
+0

Wow, ví dụ mã đó rất hữu ích, tôi nghĩ đoạn mã của riêng tôi đã hoạt động và chuỗi đã bị hủy thành công. Tuy nhiên, tôi không muốn quá phấn khởi, một thứ có thể luôn xuất hiện. :) – Chrispy

1

Với WebClient, bạn có thể sử dụng phương thức CancelAsync để hủy thao tác không đồng bộ.

Để hủy các tác vụ bạn đang bắt đầu qua Factory.StartNew, bạn nên sử dụng CancellationTokenSource. Bạn cần phải chuyển CancellationTokenSource.Token cho các tác vụ (và bạn có thể hỏi mã thông báo đã bị hủy chưa bằng cách sử dụng token.IsCancellationRequested) và bạn sẽ gọi CancellationTokenSource.Cancel() để đặt mã thông báo là đã hủy.

+0

Chúc mừng, tôi chắc chắn sẽ nhớ điều này liên quan đến Factory.StartNew – Chrispy

Các vấn đề liên quan