C# For循环导致Task.Run或Task.Start溢出

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])); } 有什么想法吗 关于山姆这可能是由心

有问题,希望有人能帮我解决

我尝试在循环中启动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
      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)中没有“闭包问题”