6

我不参与接近 O​​S 的编程技术,但据我所知,当涉及到在 Perl 中并行执行某些事情时,选择的武器是fork并且可能构建在它之上的一些有用的模块。文档页面fork说:

Does a fork(2) system call to create a new process running the same program at the same point.

因此,拥有一个消耗大量内存的大型应用程序并调用fork一个小任务意味着将有 2 个大的 perl 进程,而第二个将浪费资源只是为了做一些简单的工作。

所以,问题是:要做什么(或如何使用fork,如果它是唯一的方法)以使代码的分离部分独立运行并仅消耗它需要的资源

只是一个非常简单的例子:

    use strict;
    use warnings;

    my @big_array = ( 1 .. 2000000 );  # at least 80 MB memory
    sleep 10;  # to have time to inspect easely the memory usage

    fork();
    sleep 10;  # to have time to inspect easely the memory usage

子进程也消耗 80+ MB。

需要明确的是:与这个分离的代码进行通信或以某种方式使用它的结果并不重要,只是可以说“嘿,在后台为我运行这个简单的任务,让我同时继续我的繁重工作......并且不要浪费我的资源! ”运行繁重的 perl 应用程序时。

4

4 回答 4

3

您的分叉进程实际上并未使用 80MB 的常驻内存。该内存的很大一部分将被共享- 从父进程“借用”,直到父进程或子进程写入它,此时写入时复制语义将导致内存实际被复制。

如果你想完全放下那个包袱,exec就用你的叉子跑吧。这将用不同的可执行文件替换子 Perl 进程,从而释放内存。如果您不需要向父母传达任何信息,这也是完美的。

于 2013-02-19T17:17:04.893 回答
3

fork()toexec()是你的兔子。你fork()创建一个新进程(这是一个相当便宜的操作,见下文),然后用更小的东西替换你正在运行exec()的大进程。perl这看起来像这样:

use strict;
use warnings;
use 5.010;

my @ary = (1 .. 10_000_000);

if (my $pid = fork()) {
    # parent
    say "Forked $pid from $$; sleeping";
    sleep 1_000;
} else {
    # child
    exec('perl -e sleep 1_000');
}

@ary只是用来填充原始进程的内存。)

我说fork()ing 相对便宜,尽管它确实复制了整个原始过程。这些陈述并不冲突;设计的人fork注意到了同样的问题。复制是惰性的,即只复制实际更改的位。

如果您发现您希望进程相互通信,您将开始进入更复杂的 IPC 领域,有关该领域的书籍已经写了很多。

于 2013-02-19T17:20:45.623 回答
1

没有办法只分叉进程足迹的一个子集,因此通常的解决方法可以归结为:

  1. fork在父进程中运行内存密集型代码之前
  2. system用or开始一个单独的进程open HANDLE,'|-',...。当然,这个新进程不会从其父进程继承任何数据,因此您需要以某种方式将数据传递给该子进程。
于 2013-02-19T17:09:05.397 回答
1

fork()在大多数操作系统上实现的效果非常好。它通常使用一种称为写时复制的技术,这意味着页面最初是共享的,直到一个或其他进程写入它们。无论如何,您的很多进程内存都将是只读映射文件。

仅仅因为一个进程之前使用 80MBfork()并不意味着之后两个将使用 160。一开始它只会超过 80MB 的一小部分,直到每个进程开始污染更多页面。

于 2013-03-12T13:54:05.033 回答