并行编程和并行编程的区别是什么?我问了谷歌,但没有找到任何帮助我理解这种区别的东西。你能给我举个例子吗?

现在我找到了这个解释:http://www.linux-mag.com/id/7411 -但是“并发性是程序的属性”vs“并行执行是机器的属性”对我来说还不够-我仍然不能说什么是什么。


当前回答

不同的人在许多不同的具体情况下讨论不同类型的并发性和并行性,因此需要一些抽象来涵盖它们的共同性质。

The basic abstraction is done in computer science, where both concurrency and parallelism are attributed to the properties of programs. Here, programs are formalized descriptions of computing. Such programs need not to be in any particular language or encoding, which is implementation-specific. The existence of API/ABI/ISA/OS is irrelevant to such level of abstraction. Surely one will need more detailed implementation-specific knowledge (like threading model) to do concrete programming works, the spirit behind the basic abstraction is not changed.

第二个重要的事实是,作为一般属性,并发性和并行性可以在许多不同的抽象中共存。

关于一般的区别,请参阅并发和并行的基本观点的相关答案。(还有一些链接包含一些其他来源。)

并发编程和并行编程是用一些系统实现这些一般属性的技术,这些系统公开了可编程性。系统通常是编程语言及其实现。

A programming language may expose the intended properties by built-in semantic rules. In most cases, such rules specify the evaluations of specific language structures (e.g. expressions) making the computation involved effectively concurrent or parallel. (More specifically, the computational effects implied by the evaluations can perfectly reflect these properties.) However, concurrent/parallel language semantics are essentially complex and they are not necessary to practical works (to implement efficient concurrent/parallel algorithms as the solutions of realistic problems). So, most traditional languages take a more conservative and simpler approach: assuming the semantics of evaluation totally sequential and serial, then providing optional primitives to allow some of the computations being concurrent and parallel. These primitives can be keywords or procedural constructs ("functions") supported by the language. They are implemented based on the interaction with hosted environments (OS, or "bare metal" hardware interface), usually opaque (not able to be derived using the language portably) to the language. Thus, in this particular kind of high-level abstractions seen by the programmers, nothing is concurrent/parallel besides these "magic" primitives and programs relying on these primitives; the programmers can then enjoy less error-prone experience of programming when concurrency/parallelism properties are not so interested.

Although primitives abstract the complex away in the most high-level abstractions, the implementations still have the extra complexity not exposed by the language feature. So, some mid-level abstractions are needed. One typical example is threading. Threading allows one or more thread of execution (or simply thread; sometimes it is also called a process, which is not necessarily the concept of a task scheduled in an OS) supported by the language implementation (the runtime). Threads are usually preemptively scheduled by the runtime, so a thread needs to know nothing about other threads. Thus, threads are natural to implement parallelism as long as they share nothing (the critical resources): just decompose computations in different threads, once the underlying implementation allows the overlapping of the computation resources during the execution, it works. Threads are also subject to concurrent accesses of shared resources: just access resources in any order meets the minimal constraints required by the algorithm, and the implementation will eventually determine when to access. In such cases, some synchronization operations may be necessary. Some languages treat threading and synchronization operations as parts of the high-level abstraction and expose them as primitives, while some other languages encourage only relatively more high-level primitives (like futures/promises) instead.

Under the level of language-specific threads, there come multitasking of the underlying hosting environment (typically, an OS). OS-level preemptive multitasking are used to implement (preemptive) multithreading. In some environments like Windows NT, the basic scheduling units (the tasks) are also "threads". To differentiate them with userspace implementation of threads mentioned above, they are called kernel threads, where "kernel" means the kernel of the OS (however, strictly speaking, this is not quite true for Windows NT; the "real" kernel is the NT executive). Kernel threads are not always 1:1 mapped to the userspace threads, although 1:1 mapping often reduces most overhead of mapping. Since kernel threads are heavyweight (involving system calls) to create/destroy/communicate, there are non 1:1 green threads in the userspace to overcome the overhead problems at the cost of the mapping overhead. The choice of mapping depending on the programming paradigm expected in the high-level abstraction. For example, when a huge number of userspace threads expected being concurrently executed (like Erlang), 1:1 mapping is never feasible.

The underlying of OS multitasking is ISA-level multitasking provided by the logical core of the processor. This is usually the most low-level public interface for programmers. Beneath this level, there may exist SMT. This is a form of more low-level multithreading implemented by the hardware, but arguably, still somewhat programmable - though it is usually only accessible by the processor manufacturer. Note the hardware design is apparently reflecting parallelism, but there is also concurrent scheduling mechanism to make the internal hardware resources being efficiently used.

在上面提到的每一层“线程”中,都涉及并发性和并行性。尽管编程接口变化很大,但它们都服从于一开始基本抽象所揭示的属性。

其他回答

我认为并发编程指的是多线程编程,它是关于让你的程序运行多个线程,从硬件细节中抽象出来。

并行编程是指专门设计程序算法以利用可用的并行执行。例如,您可以并行执行某些算法的两个分支,期望它会比先检查第一个分支再检查第二个分支更快地到达结果(平均而言)。

将原始问题解释为并行/并发计算,而不是编程。

在并发计算中,两个计算都是彼此独立前进的。第二个计算不需要等到第一个计算完成后才能继续进行。但是,它并没有说明这是如何实现的机制。在单核设置中,线程之间需要挂起和交替(也称为抢占式多线程)。

在并行计算中,两个计算同时进行——字面上是同时进行。这对于单CPU来说是不可能的,而是需要多核设置。

图片来自文章:“Node.js中的并行vs并发”

并发编程是一个通用概念,即一个程序可以以未定义的完成顺序执行多个任务,并且这些任务可以同时执行,也可以不同时执行。

并行编程只是一种并发编程,其中这些任务运行在同时执行的线程上。

我真的不理解这里许多过于冗长的回答,这些回答似乎暗示并行编程和并行编程是不同的编程方法,它们并不重叠。

如果你在写一个并行程序,根据定义,你是在写一个并发程序的特殊情况。这些年来,术语似乎被不必要地混淆和复杂化了。

关于并发编程最好、最详细的报道之一是Joe Duffy所著的《Windows上的并发编程》一书。这本书定义了并发,然后继续解释各种操作系统资源,库等可用来编写“并行”程序,如。net中的任务并行库。

第5页:

并行性是使用并发性将操作分解为 粒度更细的组成部分,以便独立的部分可以运行 机器上的独立处理器"

同样,并行编程只是一种特殊类型的并发编程,其中多个线程/任务将同时运行。

PS 我一直不喜欢在编程中,并发和并行这两个词有如此多的含义。例:在编程之外的广阔世界里,“篮球比赛将并行进行”和“篮球比赛将并行进行”是完全相同的。

想象一下,在开发者大会上,他们在第一天宣传会议将“并行”运行,但第二天他们将“并发”运行,这是多么可笑的困惑。那会很搞笑的!

并发性和并行性源

在单个处理器上的多线程进程中,处理器可以在线程之间切换执行资源,从而实现并发执行。

在共享内存多处理器环境中的同一个多线程进程中,进程中的每个线程可以同时在单独的处理器上运行,从而导致并行执行。

当进程的线程数量与处理器数量相同或较少时,线程支持系统结合操作环境确保每个线程运行在不同的处理器上。

例如,在具有相同数量的线程和处理器的矩阵乘法中,每个线程(和每个处理器)计算结果的一行。

并发编程在一般意义上是指我们定义的任务可以以任何顺序发生的环境。一个 任务可以发生在另一个任务之前或之后,并且部分或所有任务可以 同时进行的。 并行编程是特指在不同的处理器上同时执行并发任务。因此,所有 并行编程是并发的,但不是所有的并发编程 是平行的。

来源:PThreads Programming -一个更好的多处理POSIX标准,Buttlar, Farrell, Nichols