ParallelOptions.CancellationToken似乎没用

时间:2016-08-28 16:07:38

标签: c# .net lambda task-parallel-library

ParallelOptions的一个成员是CancellationToken,其值应在Parallel.ForEach的lambda函数中访问。

使用它需要在调用Parallel.ForEach之前实例化CacellationToken,那么为什么不能直接在ForEach的Lambda函数中访问该局部变量?

e.g。而不是:

uniform sampler2D texture;

void main() {
    gl_FragColor = texture2D(texture, gl_TexCoord[0].st) * vec4(1,0,0,1);    
}

为什么我不能使用:

var ct = new CancellationToken();
var options = new ParallelOptions { CancellationToken = ct }

Parallel.ForEach(source, options, (item) =>
{
     options.ct.ThrowIfCancellationRequested();
})

是否只是一个存放令牌的方便地方,或者这个设计是否有一些潜在的原因?

2 个答案:

答案 0 :(得分:4)

如果您告诉Parallel.ForEach CancellationToken,则可以在取消令牌时停止处理。您可能不希望从循环中抛出异常 - 您可能只想自己忽略取消令牌,并且只是希望处理您的项目的子集。

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
        var items = Enumerable.Range(0, 100).ToList();
        Parallel.ForEach(items, new ParallelOptions { CancellationToken = cts.Token },
            item =>
            {
                Console.WriteLine(item);
                Thread.Sleep(1000);
            });
    }
}

这将在三秒后以OperationCanceledException完成(而不是AggregateException如果某个/某些单个任务失败,则会收到你的Parallel.ForEach - 但是行动机构本身并没有; t需要知道取消令牌。当然,如果你有一个昂贵的操作,你不想为完成的最终项目不必要地完成,你可以自己监控令牌,但你可以让private void button1_Click(object sender, EventArgs e) { SqlConnection con = new SqlConnection(conString); con.Open(); if (con.State == System.Data.ConnectionState.Open) { SqlCommand cmd = new SqlCommand("select * from Employee_Details where email = '"+txtEmail.Text+"' and password = '"+txtPass.Text+"'", con); SqlDataReader dr; dr = cmd.ExecuteReader(); int count = 0; while(dr.Read()) { count += 1; } if (count == 1) { con.Close(); con.Open(); SqlCommand cmd_user = new SqlCommand("select id from Employee_Details where email = '" + txtEmail.Text + "' and password = '" + txtPass.Text + "'", con); SqlDataReader reader = cmd_user.ExecuteReader(); while (reader.Read()) { string user_id = Convert.ToString(reader["id"]); } MessageBox.Show("Log in Successfull"); this.Hide(); MainMenu mn = new MainMenu(); mn.ShowDialog(); } 注意并抛出异常本身。

答案 1 :(得分:-2)

“乔恩·斯基特”的答案并非在所有情况下都正确。 来自ParallelOptions的令牌源取消,直到所有任务完成后才中断Parallel.ForEach循环。 要中断循环,您必须使用例如调用token.ThrowIfCancellationRequested()或完成所有任务的方法。