多核编程:困难的部分

发布于 2024-09-04 12:46:37 字数 64 浏览 6 评论 0原文

我正在写一本关于使用 .NET 4 进行多核编程的书,我很想知道人们发现多核编程的哪些部分难以理解或预计难以理解?

I'm writing a book on multicore programming using .NET 4 and I'm curious to know what parts of multicore programming people have found difficult to grok or anticipate being difficult to grok?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

ヤ经典坏疍 2024-09-11 12:46:38

什么是有用的并行工作单元,以及如何找到/组织一个?

如果您分叉了一项比分叉开销小的工作,那么所有这些并行原语都没有帮助;事实上,这会给你带来很好的减速,而不是你所期望的。

因此,最大的问题之一是找到明显比并行原语更昂贵的工作单元。这里的一个关键问题是,没有人知道执行任何东西的成本,包括并行原语本身。显然,校准这些成本将非常有帮助。 (顺便说一句,我们设计、实现并日常使用一种并行编程语言,PARLANSE,其目标是通过允许编译器生成和优化并行原语来最小化并行原语的成本,目标是使较小的工作“更可并行化”)。

人们还可以考虑讨论大哦表示法及其应用。我们都希望并行原语的成本为 O(1)。如果是这样的话,那么如果你发现工作成本 O(x) > O(1) 那么该工作是并行化的良好候选者。如果你提出的工作也是O(1),那么它是否有效取决于常数因子,我们又回到了上面的校准。

如果没有一个部分足够大,那么将工作收集到足够大的单元中就会出现问题。代码移动、算法替换……都是实现这种效果的有用想法。

最后,还有同步问题:我的并行单元何时必须交互,我应该使用哪些原语,以及这些原语的成本是多少? (超出您的预期!)。

What's a useful unit of work to parallelize, and how do I find/organize one?

All these parallelism primitives aren't helpful if you fork a piece of work that is smaller than the forking overhead; in fact, that buys you a nice slowdown instead of what you are expecting.

So one of the big problems is finding units of work that are obviously more expensive than the parallelism primitives. A key problem here is that nobody knows what anything costs to execute, including the parallelism primitives themselves. Clearly calibrating these costs would be very helpful. (As an aside, we designed, implemented, and daily use a parallel programming langauge, PARLANSE whose objective was to minimize the cost of the parallelism primitives by allowing the compiler to generate and optimize them, with the goal of making smaller bits of work "more parallelizable").

One might also consider discussion big-Oh notation and its applications. We all hope that the parallelism primitives have cost O(1). If that's the case, then if you find work with cost O(x) > O(1) then that work is a good candidate for parallelization. If your proposed work is also O(1), then whether it is effective or not depends on the constant factors and we are back to calibration as above.

There's the problem of collecting work into large enough units, if none of the pieces are large enough. Code motion, algorithm replacement, ... are all useful ideas to achieve this effect.

Lastly, there's the problem of synchnonization: when do my parallel units have to interact, what primitives should I use, and how much do those primitives cost? (More than you expect!).

最初的梦 2024-09-11 12:46:38

我想其中一些取决于这本书/读者的基础或高级程度。当您第一次从单线程编程转向多线程编程时,您通常会跌落悬崖(许多人再也无法恢复,请参阅有关 Control.Invoke 的所有混乱问题)。

无论如何,添加一些与编程本身无关的想法,更多地与软件过程中的其他相关任务相关:

  • 测量:决定您要改进的指标,并正确测量它(很容易意外地测量到错误的东西),使用正确的工具,区分信号与噪声,解释结果并理解为什么它们是这样的。

  • 测试:如何编写能够容忍不重要的非确定性/交错的测试,但仍能确定正确的程序行为。

  • 调试:工具、策略,当“难以调试”意味着改进代码/设计和更好地分区可变状态等时的反馈。

  • 物理与逻辑线程亲和性:了解 GUI 线程,了解如何例如,F# MailboxProcessor/代理可以封装可变状态并在多个线程上运行,但始终仅使用单个逻辑线程(一个程序计数器)。

  • 模式(以及何时应用):fork-join、map-reduce、生产者-消费者,...

我预计会有大量受众,例如“帮助,我有一个 CPU 利用率为 12% 的单线程应用程序,我想要学习足够的知识,使其速度提高 4 倍,无需太多工作”,并且受众较少,例如“当我们添加核心时,我的应用程序正在亚线性扩展,因为这里似乎存在争用,是否有更好的使用方法?”,以及因此,为每一位受众提供服务可能是一个挑战。

I guess some of it depends on how basic or advanced the book/audience is. When you go from single-threaded to multi-threaded programming for the first time, you typically fall off a huge cliff (and many never recover, see e.g. all the muddled questions about Control.Invoke).

Anyway, to add some thoughts that are less about the programming itself, and more about the other related tasks in the software process:

  • Measuring: deciding what metric you are aiming to improve, measuring it correctly (it is so easy to accidentally measure the wrong thing), using the right tools, differentiating signal versus noise, interpreting the results and understanding why they are as they are.

  • Testing: how to write tests that tolerate unimportant non-determinism/interleavings, but still pin down correct program behavior.

  • Debugging: tools, strategies, when "hard to debug" implies feedback to improve your code/design and better partition mutable state, etc.

  • Physical versus logical thread affinity: understanding the GUI thread, understanding how e.g. an F# MailboxProcessor/agent can encapsulate mutable state and run on multiple threads but always with only a single logical thread (one program counter).

  • Patterns (and when they apply): fork-join, map-reduce, producer-consumer, ...

I expect that there will be a large audience for e.g. "help, I've got a single-threaded app with 12% CPU utilization, and I want to learn just enough to make it go 4x faster without much work" and a smaller audience for e.g. "my app is scaling sub-linearly as we add cores because there seems to be contention here, is there a better approach to use?", and so a bit of the challenge may be serving each of those audiences.

断爱 2024-09-11 12:46:38

由于您写了一整本书,介绍 .Net 中的多核编程。

我认为你还可以超越多核一点。

例如,您可以使用讨论 .Net 中分布式系统中的并行计算的章节。不太可能的是,.Net 中还没有成熟的框架。 DryadLinq 是最接近的。 (另一方面,Hadoop 及其在 Java 平台上的朋友确实很棒。)

您还可以使用一章来演示一些 GPU 计算的内容。

Since you write a whole book for multi-core programming in .Net.

I think you can also go beyond multi-core a little bit.

For example, you can use a chapter talking about parallel computing in a distributed system in .Net. Unlikely, there is no mature frameworks in .Net yet. DryadLinq is the closest. (On the other side, Hadoop and its friends in Java platform are really good.)

You can also use a chapter demonstrating some GPU computing stuff.

黑色毁心梦 2024-09-11 12:46:38

让我困惑的一件事是使用哪种方法来解决特定类型的问题。有代理、有任务、异步计算、用于分发的 MPI - 对于许多问题,您可以使用多种方法,但我很难理解为什么我应该使用一种方法而不是另一种方法。

One thing that has tripped me up is which approach to use to solve a particular type of problem. There's agents, there's tasks, async computations, MPI for distribution - for many problems you could use multiple methods but I'm having difficulty understanding why I should use one over another.

夜未央樱花落 2024-09-11 12:46:38

理解:低级内存细节,例如内存获取和释放语义之间的差异。

其余的大部分概念和想法(任何东西都可以交织、竞争条件……)只要稍微使用一下就不那么困难了。

当然,实践非常困难,特别是有时出现故障时,因为您需要在多个抽象级别上工作才能了解正在发生的情况,因此请保持设计简单,并尽可能设计出锁定等的需要。 (例如使用不可变数据和更高级别的抽象)。

To understand: low level memory details like the difference between acquire and release semantics of memory.

Most of the rest of the concepts and ideas (anything can interleave, race conditions, ...) are not that difficult with a little usage.

Of course the practice, especially if something is failing sometimes, is very hard as you need to work at multiple levels of abstraction to understand what is going on, so keep your design simple and as far as possible design out the need for locking etc. (e.g. using immutable data and higher level abstractions).

寄离 2024-09-11 12:46:38

与其说是理论细节,不如说是令人困惑的实际实施细节。

不可变数据结构是怎么回事?

一直以来,人们尝试从多个线程更新数据结构,发现这太难了,有人插话“使用不可变数据结构!”,所以我们的持久编码器这样写:

ImmutableSet set;

ThreadLoop1()
    foreach(Customer c in dataStore1)
        set = set.Add(ProcessCustomer(c));

ThreadLoop2()
    foreach(Customer c in dataStore2)
        set = set.Add(ProcessCustomer(c));

编码器一生都听说不可变数据结构可以在不锁定的情况下更新,但新代码由于明显的原因不起作用。

即使您的目标是学者和经验丰富的开发人员,了解一些不可变编程习惯的基础知识也不会造成什么伤害。

如何在线程之间分配大致相等的工作量?

正确执行此步骤很难。有时,您将一个流程分解为 10,000 个可以并行执行的步骤,但并非所有步骤都花费相同的时间。如果您将工作分成 4 个线程,前 3 个线程在 1 秒内完成,最后一个线程需要 60 秒,那么您的多线程程序并不比单线程版本好多少,对吗?

那么如何在所有线程之间分配大致相等的工作量的问题呢?关于解决装箱问题的许多好的启发法应该与这里有关。

有多少线程?

如果您的问题可以很好地并行化,那么添加更多线程应该会使它更快,对吗?好吧,不是真的,这里需要考虑很多事情:

即使是单核处理器,添加更多线程也可以使程序更快,因为更多线程为操作系统提供了更多机会来调度线程,因此它比单线程获得更多的执行时间程序。但根据收益递减规律,添加更多线程会增加上下文切换,因此在某个时刻,即使您的程序具有最多的执行时间,性能仍然可能比单线程版本更差。

那么如何分出足够的线程来最大限度地减少执行时间呢?

如果有许多其他应用程序旋转线程并竞争资源,您如何检测性能变化并自动调整您的程序?

Its not so much theoretical details, but more the practical implementation details which trips people up.

What's the deal with immutable data structures?

All the time, people try to update a data structure from multiple threads, find it too hard, and someone chimes in "use immutable data structures!", and so our persistent coder writes this:

ImmutableSet set;

ThreadLoop1()
    foreach(Customer c in dataStore1)
        set = set.Add(ProcessCustomer(c));

ThreadLoop2()
    foreach(Customer c in dataStore2)
        set = set.Add(ProcessCustomer(c));

Coder has heard all their lives that immutable data structures can be updated without locking, but the new code doesn't work for obvious reasons.

Even if your targeting academics and experienced devs, a little primer on the basics of immutable programming idioms can't hurt.

How to partition roughly equal amounts of work between threads?

Getting this step right is hard. Sometimes you break up a single process into 10,000 steps which can be executed in parallel, but not all steps take the same amount of time. If you split the work on 4 threads, and the first 3 threads finish in 1 second, and the last thread takes 60 seconds, your multithreaded program isn't much better than the single-threaded version, right?

So how do you partition problems with roughly equal amounts of work between all threads? Lots of good heuristics on solving bin packing problems should be relevant here..

How many threads?

If your problem is nicely parallelizable, adding more threads should make it faster, right? Well not really, lots of things to consider here:

Even a single core processor, adding more threads can make a program faster because more threads gives more opportunities for the OS to schedule your thread, so it gets more execution time than the single-threaded program. But with the law of diminishing returns, adding more threads increasing context-switching, so at a certain point, even if your program has the most execution time the performance could still be worse than the single-threaded version.

So how do you spin off just enough threads to minimize execution time?

And if there are lots of other apps spinning up threads and competing for resources, how do you detect performance changes and adjust your program automagically?

你与清晨阳光 2024-09-11 12:46:38

我发现同步数据以复杂模式在工作节点之间移动的概念非常难以可视化和编程。

通常我也觉得调试很麻烦。

I find the conceptions of synchronized data moving across worker nodes in complex patterns very hard to visualize and program.

Usually I find debugging to be a bear, also.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文