为什么C#线程无法在多个内核上正常运行?

时间:2019-05-23 22:23:30

标签: c# multithreading

我的代码有点复杂,但是核心是这样启动线程的:

Thread task = new Thread(new ParameterizedThreadStart(x => { ThreadReturn = BuildChildNodes(x); }));
task.Start((NodeParameters)tasks[0]);

它应该工作。但是当我检查我的CPU使用率时,我的收益只有10%。所以我确实假设它仅使用一个内核。勉强。

ThreadReturn btw是一个值,我在线程准备就绪时使用setter来发生某种事件:

public object ThreadReturn
        {
            set
            {
                lock (thisLock)
                {
                    NodeReturn result = (NodeReturn)value;
                    if (result.states.Count == 0) return;
                    Content[result.level + 1].AddRange(result.states);
                    if (result.level + 1 >= MaxDepth) return;
                    for (int i = 0; i < result.states.Count; i++)
                    {
                        Thread newTask = new Thread(new ParameterizedThreadStart(x => ThreadReturn = BuildChildNodes(x)));
                        NodeParameters param = new NodeParameters()
                        {
                            level = result.level + 1,
                            node = Content[result.level + 1].Count - (i + 1),
                            turn = SkipOpponent ? StartTurn : !result.turn
                        };
                        if (tasks.Count > 100)
                            unstarted.Add(param);
                        else
                        {
                            newTask.Start(param);
                            tasks.Add(newTask);
                        }
                    }
                }
            }
        }

我遇到了一些关于标记堆栈溢出的疯狂错误,因此我将并行任务的最大数量限制在第二个列表中... 我不确定多线程,所以这段代码有点混乱……也许您可以向我展示一种更好地使用我的内核的方法。

btw:这不是锁故障。我没有尝试过。 ->相同结果

编辑:这是我上Threading类之前的代码。我觉得它更合适:

Content.Clear();
        Content.Add(new List<T> { Root });
        for (var i = 0; i < maxDepth; i++)
            Content.Add(new List<T>());
        Task<object> firstTask = new Task<object>(x => BuildChildNodes(x), (new NodeParameters() { level = 0, node = 0, turn = Turn }));
        firstTask.Start();
        tasks.Add(firstTask);
        while (tasks.Count > 0 && Content.Last().Count == 0)
        {
            Task.WaitAny(tasks.ToArray());
            for (int task = tasks.Count - 1; task >= 0; task--)
            {
                if (tasks[task].IsCompleted)
                {
                    NodeReturn result = (NodeReturn)tasks[task].Result;
                    tasks.RemoveAt(task);
                    Content[result.level + 1].AddRange(result.states);
                    if (result.level + 1 >= maxDepth) continue;
                    for (int i = 0; i < result.states.Count; i++)
                    {
                        Task<object> newTask = new Task<object>(x => BuildChildNodes(x), (object)new NodeParameters() { level = result.level + 1, node = Content[result.level + 1].Count - (i + 1), turn = SkipOpponent ? Turn : !result.turn });
                        newTask.Start();
                    }
                }
            }
        }

在每种状态下,我正在计算子级,在主线程中,我将它们放入状态树中,同时等待任务完成。请假设我实际上会使用waitany的返回值,我进行了git reset,现在...好吧...它消失了^^

编辑: 好吧,我不知道我到底做错了什么,但是...总的来说,一切都是一团糟。我现在实现了深度构造方法,也许是因为它要少得多……“流量”现在我的整个代码在200毫秒内运行。所以...谢谢你!

我不知道我是否应该删除这个问题,以免愚蠢,或者你们是否想发布答案,以便我对它们表示肯定,您确实对我有很大帮助:)

1 个答案:

答案 0 :(得分:1)

忽略此处遇到的所有其他问题。本质上,您的lock破坏了演出。

您的意思是,嘿,随便的人去做点事吧!只需确保您不与其他任何人(lock)同时执行此操作,则可以有1000个线程,但是在一个内核上一次只能有一个线程处于活动状态,因此结果< / p>

还有其他想法。

  1. 摆脱设置器的麻烦,这将使任何理智的代码审查失败。
  2. 使用 Tasks 代替Thread
  3. 考虑什么需要线程安全,并且优雅地lock仅需要它,看看Interlocked处理数字原子操作
  4. 看看concurrent collections,您可能会因此而受益匪浅
  5. 简化代码。

我无法提供更多建议,因为它几乎无法知道您要做什么。