【问题标题】:C# Task.Run skips values, is missing data, when doing many iterationsC# Task.Run 在进行多次迭代时跳过值,丢失数据
【发布时间】:2019-05-17 22:06:59
【问题描述】:

在使用 Task.Run 对同一函数进行数千次迭代时,跟踪某个值增加了多少次时的最终结果导致总迭代次数与该值增加了多少次不匹配.为什么?怎么修?建议的替代方法?我的目标只是尽可能快地在多线程环境中运行相同的功能。

下面的代码示例显示了我现在正在尝试的内容,您应该能够按原样运行它以看到与我看到的相似的结果:

taskNumber = 9980, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 9998, nonTaskIterations = 10000
taskNumber = 9998, nonTaskIterations = 10000
taskNumber = 9999, nonTaskIterations = 10000
taskNumber = 9997, nonTaskIterations = 10000
taskNumber = 9999, nonTaskIterations = 10000
taskNumber = 9997, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 9995, nonTaskIterations = 10000
taskNumber = 9994, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 9998, nonTaskIterations = 10000
taskNumber = 9999, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 9999, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
    static void Main(string[] args)
    {
        for (int i = 0; i < 20; i++)
        {
            //iterate many times to see different outputs
            PrimaryFunction();
        }

        Console.WriteLine("why the hell does TaskNumber not always == nonTaskIterations value?");
        Console.ReadLine();
    }

    static void PrimaryFunction()
    {
        long taskNumber = 0;
        int nonTaskIterations = 0;

        for (int i = 0; i < 100; i++)
        {
            List<Task> tasks = new List<Task>();
            for (int j = 0; j < 100; j++)
            {
                nonTaskIterations++;
                tasks.Add(Task.Run(() =>
                {
                    taskNumber = taskNumber + 1;
                    DoWork(taskNumber);
                }));
            }

            Task.WaitAll(tasks.ToArray());
        }

        Console.WriteLine("taskNumber = " + taskNumber + ", nonTaskIterations = " + nonTaskIterations);
    }

    static void DoWork(long i)
    {
        //do work here
        Random random = new Random();
        var x = random.Next(0, 10).ToString();
    }

我希望每次运行时都能看到:

taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000
taskNumber = 10000, nonTaskIterations = 10000

我乐于接受有关如何修复此问题或替代方法的建议,这些方法也既快速高效又准确,可以反复运行多线程环境函数数千次而不会丢失任何增量值。

【问题讨论】:

    标签: c# multithreading c#-4.0 task


    【解决方案1】:

    这根本不是线程安全的(我相信你自己已经得出了这个结论)。您不能期望多个 cores 上的多个 threadscache

    中始终具有相同的值

    获得期望值的一种方法是使用Interlocked.Increment,它充当内存屏障,消除处理器围绕指令重新排序内存访问的能力,进而确保增量操作是原子的

    递增指定变量并将结果存储为原子 操作。

    Interlocked.Increment(ref someValue);
    

    输出

    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    taskNumber = 10000, nonTaskIterations = 10000
    

    Full Demo Here

    【讨论】:

      猜你喜欢
      • 2019-05-06
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 2017-06-18
      • 2014-10-30
      • 1970-01-01
      • 2013-10-03
      相关资源
      最近更新 更多