【问题标题】:Child tasks are not awaited by parent task父任务不等待子任务
【发布时间】:2014-03-02 00:55:36
【问题描述】:

这是我的代码

static void Main(string[] args)
{
    List<Thing> collection = new List<Thing>
    { 
        new Thing { IntProp = 1, BoolProp = true }, 
        new Thing { IntProp = 1, BoolProp = true }, 
        new Thing { IntProp = 2, BoolProp = true }, 
        new Thing { IntProp = 1, BoolProp = false } 
    };

    int number = 0;

    var task = Task.Factory.StartNew<bool>(() =>
    {
        TaskFactory ts = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);

        foreach (var item in collection)
        {
            if (item.BoolProp)
            {
                ts.StartNew(() =>
                    number += GetNum1(item.IntProp));
            }
            else
            {
                ts.StartNew(() =>
                    number += GetNum2(item.IntProp));
            }
        }

        return true;
    });

    task.Wait();

    Console.WriteLine(number);
}

这里是GetNum1GetNum2的定义

static int GetNum1(int num)
{
    for (int i = 0; i < 1000000000; i++) { } // simulate some job

    return 10;
}

static int GetNum2(int num)
{
    for (int i = 0; i < 500000000; i++) { } // simulate some job

    return 3;
}

这是Thing

class Thing
{
    public bool BoolProp { get; set; }
    public int IntProp { get; set; }
}

基本上我所做的只是创建Thing 对象的集合。然后我创建一个父任务,它将有几个子任务(我猜它应该等待)。

有一个number 变量,它由子任务增加从GetNum1GetNum2 方法(10 或3)返回的数量。我猜上面的代码应该输出 33 (10 + 10 + 10 + 3),但是输出的是 10,因为只等待第一个子任务。如果我将断点放在代码中并逐步执行,则输出是正确的。为什么会发生这种情况。它是否必须与父任务中的 foreach 循环有关?请不要开始问“为什么需要这个”和“不需要那个”之类的问题,这只是一个示例代码。

【问题讨论】:

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


    【解决方案1】:

    父任务实际上正在等待(而不是“等待”)子任务。您的问题是代码正在从多个线程访问 number 变量而没有同步:

    var mutex = new object();
    int number = 0;
    
    var task = Task.Factory.StartNew<bool>(() =>
    {
        TaskFactory ts = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously);
    
        foreach (var item in collection)
        {
            if (item.BoolProp)
            {
                ts.StartNew(() =>
                {
                    var value = GetNum1(item.IntProp);
                    lock (mutex) number += value;
                });
            }
            else
            {
                ts.StartNew(() =>
                {
                    var value = GetNum2(item.IntProp);
                    lock (mutex) number += value;
                });
            }
        }
    
        return true;
    });
    
    task.Wait();
    
    lock (mutex)
        Console.WriteLine(number);
    

    推荐阅读:Parallel TasksDynamic Task Parallelism

    【讨论】:

    • 我在 Console.WriteLine() 之前尝试不使用 lock (mutex) 仍然可以得到结果 33
    • @V-SHY:在读取时跳过lock 有时可行,但线程本地缓存会在高级硬件上搞砸。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    相关资源
    最近更新 更多