C# For循环导致Task.Run或Task.Start溢出
有问题,希望有人能帮我解决 我尝试在循环中启动4个任务,但我得到ArgumentOutOfRangeException:C# For循环导致Task.Run或Task.Start溢出,c#,task,C#,Task,有问题,希望有人能帮我解决 我尝试在循环中启动4个任务,但我得到ArgumentOutOfRangeException: for (int i = 0; i < 4; i++) { //start task with current connection tasks[i] = Task<byte[]>.Run(() => GetData(i, plcPool[i])); } 有什么想法吗 关于山姆这可能是由心
for (int i = 0; i < 4; i++)
{
//start task with current connection
tasks[i] = Task<byte[]>.Run(() => GetData(i, plcPool[i]));
}
有什么想法吗
关于山姆这可能是由心脏病引起的
试试这个:
for (int i = 0; i < 4; i++)
{
//start task with current connection
int index = i;
tasks[index] = Task<byte[]>.Run(() => GetData(index, plcPool[index]));
}
它通常会为您提供这种输出:
Starting.
Finished. Press <ENTER> to exit.
4
4
4
4
启动。
完成了。按退出。
4.
4.
4.
4.
将该代码更改为:
public static void Main()
{
Console.WriteLine("Starting.");
for (int i = 0; i < 4; ++i)
{
int j = i;
Task.Run(() => Console.WriteLine(j));
}
Console.WriteLine("Finished. Press <ENTER> to exit.");
Console.ReadLine();
}
publicstaticvoidmain()
{
控制台。写线(“开始”);
对于(int i=0;i<4;++i)
{
int j=i;
Task.Run(()=>Console.WriteLine(j));
}
控制台。WriteLine(“完成。按退出”);
Console.ReadLine();
}
你会得到这样的结果
Starting.
Finished. Press <ENTER> to exit.
0
1
3
2
启动。
完成了。按退出。
0
1.
3.
2.
请注意,它仍然不一定是有序的!您将看到打印出的所有正确值,但顺序不确定。多线程是很棘手的 它可能是由一个错误引起的
试试这个:
for (int i = 0; i < 4; i++)
{
//start task with current connection
int index = i;
tasks[index] = Task<byte[]>.Run(() => GetData(index, plcPool[index]));
}
它通常会为您提供这种输出:
Starting.
Finished. Press <ENTER> to exit.
4
4
4
4
启动。
完成了。按退出。
4.
4.
4.
4.
将该代码更改为:
public static void Main()
{
Console.WriteLine("Starting.");
for (int i = 0; i < 4; ++i)
{
int j = i;
Task.Run(() => Console.WriteLine(j));
}
Console.WriteLine("Finished. Press <ENTER> to exit.");
Console.ReadLine();
}
publicstaticvoidmain()
{
控制台。写线(“开始”);
对于(int i=0;i<4;++i)
{
int j=i;
Task.Run(()=>Console.WriteLine(j));
}
控制台。WriteLine(“完成。按退出”);
Console.ReadLine();
}
你会得到这样的结果
Starting.
Finished. Press <ENTER> to exit.
0
1
3
2
启动。
完成了。按退出。
0
1.
3.
2.
请注意,它仍然不一定是有序的!您将看到打印出的所有正确值,但顺序不确定。多线程是很棘手的
在C#5中,foreach的循环变量在逻辑上位于循环内部,因此每次闭包都会在变量的新副本上关闭不会更改“for”循环。
另一种方式是:
internal class Program
{
private static void Main(string[] args)
{
Task[] tasks = new Task[4];
for (int i = 0; i < 4; i++)
{
//start task with current connection
tasks[i] = new Task<byte[]>(GetData,i);
}
foreach (var task in tasks)
{
task.Start();
}
Task.WaitAll(tasks);
Console.Read();
}
private static byte[] GetData(object index)
{
var i = (int) index;
switch (i)
{
case 0:
//return plc.ReadBytes(DataType.DataBlock, 50, 0, 200);
Console.WriteLine(i);
return new byte[] { };
case 1:
//return plc.ReadBytes(DataType.DataBlock, 50, 200, 200);
case 2:
Console.WriteLine(i);
return new byte[] { };
//return plc.ReadBytes(DataType.DataBlock, 50, 500, 200);
case 3:
Console.WriteLine(i);
return new byte[] { };
//return plc.ReadBytes(DataType.DataBlock, 50, 700, 200);
case 4:
//return plc.ReadBytes(DataType.DataBlock, 50, 900, 117);
Console.WriteLine(i);
return new byte[] { };
default:
return null;
}
}
}
内部类程序
{
私有静态void Main(字符串[]args)
{
任务[]任务=新任务[4];
对于(int i=0;i<4;i++)
{
//使用当前连接启动任务
任务[i]=新任务(GetData,i);
}
foreach(任务中的var任务)
{
task.Start();
}
Task.WaitAll(任务);
Console.Read();
}
私有静态字节[]GetData(对象索引)
{
VarI=(int)指数;
开关(一)
{
案例0:
//返回plc.ReadBytes(DataType.DataBlock,50,0,200);
控制台写入线(i);
返回新字节[]{};
案例1:
//返回plc.ReadBytes(DataType.DataBlock,50200200);
案例2:
控制台写入线(i);
返回新字节[]{};
//返回plc.ReadBytes(DataType.DataBlock,50500200);
案例3:
控制台写入线(i);
返回新字节[]{};
//返回plc.ReadBytes(DataType.DataBlock,50700200);
案例4:
//返回plc.ReadBytes(DataType.DataBlock,50900117);
控制台写入线(i);
返回新字节[]{};
违约:
返回null;
}
}
}
输出:
3
1
0
2
3.
1.
0
2.
注:它是新任务(GetData,i)代码>非新任务(()=>GetData(i))代码>
()=>v表示“返回变量v的当前值”,而不是“返回创建委托时v返回的值”闭包关闭变量,而不是关闭值
因此,新任务(GetData,i)代码>没有“闭包问题”
在C#5中,foreach的循环变量在逻辑上位于循环内部,因此每次闭包都会在变量的新副本上关闭不会更改“for”循环。
另一种方式是:
创建任务
运行任务李>
等待所有任务完成
演示代码如下所示:
internal class Program
{
private static void Main(string[] args)
{
Task[] tasks = new Task[4];
for (int i = 0; i < 4; i++)
{
//start task with current connection
tasks[i] = new Task<byte[]>(GetData,i);
}
foreach (var task in tasks)
{
task.Start();
}
Task.WaitAll(tasks);
Console.Read();
}
private static byte[] GetData(object index)
{
var i = (int) index;
switch (i)
{
case 0:
//return plc.ReadBytes(DataType.DataBlock, 50, 0, 200);
Console.WriteLine(i);
return new byte[] { };
case 1:
//return plc.ReadBytes(DataType.DataBlock, 50, 200, 200);
case 2:
Console.WriteLine(i);
return new byte[] { };
//return plc.ReadBytes(DataType.DataBlock, 50, 500, 200);
case 3:
Console.WriteLine(i);
return new byte[] { };
//return plc.ReadBytes(DataType.DataBlock, 50, 700, 200);
case 4:
//return plc.ReadBytes(DataType.DataBlock, 50, 900, 117);
Console.WriteLine(i);
return new byte[] { };
default:
return null;
}
}
}
内部类程序
{
私有静态void Main(字符串[]args)
{
任务[]任务=新任务[4];
对于(int i=0;i<4;i++)
{
//使用当前连接启动任务
任务[i]=新任务(GetData,i);
}
foreach(任务中的var任务)
{
task.Start();
}
Task.WaitAll(任务);
Console.Read();
}
私有静态字节[]GetData(对象索引)
{
VarI=(int)指数;
开关(一)
{
案例0:
//返回plc.ReadBytes(DataType.DataBlock,50,0,200);
控制台写入线(i);
返回新字节[]{};
案例1:
//返回plc.ReadBytes(DataType.DataBlock,50200200);
案例2:
控制台写入线(i);
返回新字节[]{};
//返回plc.ReadBytes(DataType.DataBlock,50500200);
案例3:
控制台写入线(i);
返回新字节[]{};
//返回plc.ReadBytes(DataType.DataBlock,50700200);
案例4:
//返回plc.ReadBytes(DataType.DataBlock,50900117);
控制台写入线(i);
返回新字节[]{};
违约:
返回null;
}
}
}
输出:
3
1
0
2
3.
1.
0
2.
注:它是新任务(GetData,i)代码>非新任务(()=>GetData(i))代码>
()=>v表示“返回变量v的当前值”,而不是“返回创建委托时v返回的值”闭包关闭变量,而不是关闭值
因此,新任务(GetData,i)代码>中没有“闭包问题”“