[PLINQ]取消執行

PLINQ 取消執行

PLINQ通常都是使用在大量資料查詢的時候,所以會發生一個查詢花費很長的時間。 PLINQ 有提供WithCancellation方法,程式師可以強制將查詢取消。

將cancellation tokens傳入WithCancellation()方法,然後從外部執行取消的動作,就可以取消。  取消後會拋出OperationCanceledException,所以要記得catch OperationCanceledException做後續處理。

範例如下:

public void Run()
{
    int[] source = Enumerable.Range(1, 1000000).ToArray();

    // 使用CancellationTokenSource 產生Token傳入WithCancellation
    using (CancellationTokenSource cts = new CancellationTokenSource())
    {                
        // 這在邊先開一個非同步任務做取消的觸發動作
        Task.Factory.StartNew(
            () => this.UserClicksTheCancelButton(cts)
        );

        double[] results = null;

        try
        {
            results = (from num in source.AsParallel()
                            .WithCancellation(cts.Token) // 傳入Token
                        where num % 3 == 0
                        select Function(num, cts.Token)).ToArray();
        }
        catch (OperationCanceledException e) // 取消後會拋出 OperationCanceledException
        {
            Console.WriteLine(e.Message);
            Console.WriteLine("已取消執行");
        }                

        if (results != null)
        {
            foreach (var item in results)
            {
                Console.WriteLine(item);
            }
        }

    }
                
}

private double Function(int num, CancellationToken cts)
{
    for (int i = 0; i < 50; i++)
    {
        // 假設執行很長時間
        Thread.Sleep(1000);
            
        Console.WriteLine(i);

        // 檢查是否取消了
        cts.ThrowIfCancellationRequested();
    }

    return Math.Sqrt(num);
}

private void UserClicksTheCancelButton(CancellationTokenSource cts)
{                
    Console.WriteLine("Press 'c' to cancel");
    if (Console.ReadKey().KeyChar == 'c')
    {
        // 執行取消動作
        cts.Cancel();
    }
}

 

當取消查詢的時候,已經完成的任務就完成了,沒辦法退回,而已經開始執行的任務會被允許完成。 最後尚未排入的任務,則不會執行。

 

 

 

一天一分享,身體好健康。

該追究的不是過去的原因,而是現在的目的。