在 perl、Parallel::ForkManager 或线程中哪个更快?

Aru*_*air 1 perl multithreading fork

线程被认为是轻量级进程。它们实际上会比相同数量的分叉进程运行得更快吗?

amo*_*mon 6

线程被认为是轻量级进程。

哦不,他们不是。Perl 线程模型与forkWindows 系统上的模拟交织在一起。在许多方面,在 Perl 中生成一个新线程与分叉一个新进程的行为相同:两个结果控制流都在单独的perl 解释器中运行。也就是说,整个程序状态被复制以创建一个新的解释器。

它们实际上会比相同数量的分叉进程运行得更快吗?

不见得。生成新线程是软件端的,由 perl 完成。分叉是由操作系统(在 *nix 系统上)完成的,它可以利用写时复制技术。这可以使分叉便宜得多。一个小测试:

$ time perl -Mthreads -e'threads->new(sub{threads->exit})->detach for 1 .. 5E3'
real    0m10.651s
user    0m16.421s
sys     0m1.904s
$ time perl -Mthreads -e'fork || exit  for 1 .. 5E3'
real    0m2.347s
user    0m0.032s
sys     0m0.516s
Run Code Online (Sandbox Code Playgroud)

这产生了五千个线程/进程。由于它在 Linux 上进行了测试,结果证明生成一个新进程更快。在其他操作系统上可能不是这种情况。

这并不是说 Perl 线程没有用:它们提供了许多好处,例如可选共享数据、传递数据的队列、管理共享资源的信号量、线程可以返回值等。在进程之间共享数据的最简单方法(无需using modules) 是pipe创建两个链接文件句柄的内置函数。


不要混淆彼此不同的词thread的解释:

  • 内核线程是硬件级别的执行线。它们通常不是调度的,而是并行运行的。每个处理器至少有一个线程。

  • 操作系统线程由操作系统提供。现代操作系统自己调度线程执行(抢占式调度)。通常,所有数据都是共享的,线程只是具有不同的堆栈。Perl 线程选择不强调共享属性。

  • 软件线程,也是绿色线程,由软件本身调度,通常是通过协作调度。许多具有廉价线程的语言都选择这种模型,例如 Go。两个绿色线程不一定并行运行。协程和绿色线程实际上是相关的概念:两者都描述了并发执行路径。

    软件线程有时可以比操作系统线程运行得更快,因为软件可以进行上下文切换在程序中方便的位置。(OS 线程或进程之间的抢占式切换成本更高,因为 OS 内核必须定期运行,并且每次上下文切换时都必须使用另一个线程的数据更新处理器缓存和寄存器。这在什么时候无关紧要编写常规应用程序代码)

    Perl 线程通常不使用此模型,但是存在用于协程的模块 ( Coro)。