2016-01-22 155 views
1

我打電話給一些代碼Parallel.Foreach()。代碼有Thread.Sleep(60000),所以如果我也取消了令牌,那麼它在取消Parallel.ForEach循環之前等待60秒。 Thread.Sleep()是放在這段代碼中的解釋。實際的代碼有一些等待其他資源的代碼。 我想取消所有活動,因爲調用了cts.Cancel();如何立即終止Parallel.ForEach線程?

我也嘗試過LoopState,但它不會在我的情況下工作。

using System; 
    using System.Linq; 
    using System.Threading; 
    using System.Threading.Tasks; 

    class Program 
    { 
     static void Main() 
     { 
      int[] nums = Enumerable.Range(0, 10000000).ToArray(); 
      CancellationTokenSource cts = new CancellationTokenSource(); 

      // Use ParallelOptions instance to store the CancellationToken 
      ParallelOptions po = new ParallelOptions(); 
      po.CancellationToken = cts.Token; 
      po.MaxDegreeOfParallelism = System.Environment.ProcessorCount; 
      Console.WriteLine("Press any key to start. Press 'c' to cancel."); 
      Console.ReadKey(); 

      // Run a task so that we can cancel from another thread. 
      Task.Factory.StartNew(() => 
      { 
       if (Console.ReadKey().KeyChar == 'c') 
       { 
        cts.Cancel(); 
       } 
       Console.WriteLine("press any key to exit"); 
      }); 

      try 
      { 
       Parallel.ForEach(nums, po, (num) => 
       { 
        double d = Math.Sqrt(num); 
        Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId); 
        Thread.Sleep(60000); //Thread Sleep for 1 minute 
        po.CancellationToken.ThrowIfCancellationRequested(); 
       }); 
      } 
      catch (OperationCanceledException e) 
      { 
       Console.WriteLine(e.Message); 
      } 
      finally 
      { 
       cts.Dispose(); 
      } 

      Console.ReadKey(); 
     } 
    } 
+3

如果有人告訴你使用'Thread.Abort()',把它們趕走。 –

+0

@MatthewWatson如果main()的所有代碼都在一個線程下運行,那麼Thread.Abort()將工作。 –

+2

你基本上不能這樣做,因爲沒有(理智的)方式來中斷一些不參與合作取消的代碼。通常你會讓線程繼續,但不要再等待它(並忽略它的結果),但是用'Parallel.ForEach'做到這一點並不容易。' –

回答

2

如果我理解正確的,它是不是真的,你需要中斷線程立即,而是你只是希望能夠中斷Sleep()方法,同時它的等待。

有多種選擇,但最簡單恕我直言之一是使用CancellationToken.WaitHandle屬性值,並等待上,而不是睡眠:

po.CancellationToken.WaitHandle.WaitOne(60000); 

如果令牌信號,該Wait()方法在指定的超時之前返回(在這種情況下爲一分鐘)。

通常你會檢查返回值,所以你可以分辨處理信號和等待超時之間的差異,但在你的情況下,你立即調用po.CancellationToken.ThrowIfCancellationRequested();,所以我認爲忽略返回值來自Wait()方法,並讓下一個程序語句負責實際中斷該方法。

+0

很好用WaitHandle.WaitOne()而不是Thread.Sleep()。但我必須檢查爲什麼IndexOf()花費了很多時間。我有一些像100KB字符串這樣的大數據。 –

+2

您提供的代碼示例不使用'IndexOf()',因此這顯然超出了您提出的問題的範圍。如果你有一些其他的代碼,並且你希望在調用IndexOf()時能夠中斷它,那麼你需要編寫你自己的版本,你可以通過'CancellationToken'來傳遞它,它可以在處理過程中使用以允許自己被中斷。 –

+0

有些時候IndexOf()以秒爲單位返回結果,一些時間花費了超過30秒。我使用了IndexOf()的所有組合。 –