multithreading - perl fork()似乎没有利用内核,而只有cpu

标签 multithreading perl fork

我有一个perl程序,试图将一堆文件从一种格式转换为另一种格式(通过命令行工具)。它可以正常工作,但是太慢了,因为它一次又一次地转换文件。

我研究并利用fork()机制尝试产生所有转换,作为希望利用cpu/cores的子 fork 。

编码已经完成并经过测试,它确实可以提高性能,但并没有达到我期望的方式。
当查看/proc/cpuinfo时,我有以下内容:

> egrep -e "core id" -e ^physical /proc/cpuinfo|xargs -l2 echo|sort -u
physical id : 0 core id : 0
physical id : 0 core id : 1
physical id : 0 core id : 2
physical id : 0 core id : 3
physical id : 1 core id : 0
physical id : 1 core id : 1
physical id : 1 core id : 2
physical id : 1 core id : 3

那意味着我每个都有2个CPU和四核?如果是这样,我应该能够派出8个分支,并且应该能够完成8分钟的工作(每个文件1分钟,8个文件)以1分钟的时间完成(8个分支,每个文件1个文件)。

但是,当我进行测试时,仍然需要4分钟才能完成。看来它只使用了2个CPU,但没有使用内核?

因此,我的问题是:
  • 是真的,perl的fork()仅基于CPU而不是内核并行吗?还是我做错了?我只是在使用fork()和wait()。没什么特别的。
  • 我假设perl的fork()应该使用内核,是否可以编写一个简单的bash/perl来证明我的操作系统(即RedHat 4),或者Perl是导致这种症状的罪魁祸首?

  • 添加:

    我什至尝试多次运行以下命令来模拟多个处理并监视htop。
    while true; do echo abc >>devnull; done &
    

    htop告诉我我有16个内核?然后当我生成上述while循环中的4个时,我看到其中的4个各自使用了约100%的CPU。当我产生更多时,所有这些都开始均匀地降低cpu利用率百分比。 (例如8个处理过程,请在htop中查看8个bash,但每个使用〜50%)这是否表示某些意思?

    谢谢你我尝试了Google,但找不到明显的答案。

    编辑:2016-11-09

    这是perl代码的摘录。我很想看看我在这里做错了什么。
    my $maxForks = 50;
    my $forks = 0;
    while(<CIFLIST>) {
        extractPDFByCIF($cifNumFromIndex, $acctTypeFromIndex, $startDate, $endDate);
    }
    for (1 .. $forks) {
        my $pid = wait();
        print "Child fork exited.  PID=$pid\n";
    }
    
    sub extractPDFByCIF {
        # doing SQL constructing to for the $stmt to do a DB query
        $stmt->execute();
    
        while ($stmt->fetch()) {
            # fork the copy/afp2web process into child process
            if ($forks >= $maxForks) {
                my $pid = wait();
                print "PARENTFORK: Child fork exited.  PID=$pid\n";
                $forks--;
            }
            my $pid = fork;
            if (not defined $pid) {
                warn "PARENTFORK: Could not fork.  Do it sequentially with parent thread\n";
            }
            if ($pid) {
                $forks++;
                print "PARENTFORK: Spawned child fork number $forks. PID=$pid\n";
            }else {
                print "CHILDFORK: Processing child fork. PID=$$\n";
                # prevent child fork to destroy dbh from parent thread
                $dbh->{InactiveDestroy} = 1;
                undef $dbh;
    
                # perform the conversion as usual
                if($fileName =~ m/.afp/){
                        system("file-conversion -parameter-list");
                } elsif($fileName =~ m/.pdf/) {
                        system("cp $from-file $to-file");
                } else {
                        print ERRORLOG "Problem happened here\r\n";
                }
                exit;
            }
            # end forking
    
        $stmt->finish();
        close(INDEX);
    }
    

    最佳答案

    fork()产生一个新进程-与现有进程相同,并且状态相同。不多不少。内核调度它并在任何地方运行它。

    如果您没有获得预期的结果,那么我建议一个更可能的限制因素是您正在从磁盘子系统中读取文件-磁盘速度很慢,而争夺IO并没有使它们变得更快-如果存在相反的情况,则因为它会强制执行其他驱动器查找,并且不那么容易进行缓存。

    因此,具体来说:

    1/不,fork()除了克隆您的进程外没有其他作用。

    2/在很大程度上没有意义,除非您想将大部分算法重写为Shell脚本。没有真正的理由认为这会有所不同。

    要继续进行修改,请执行以下操作:

  • system('file-conversion')看起来非常像基于IO的进程,该过程将受到磁盘IO的限制。就像你的cp一样。
  • 您是否考虑过 Parallel::ForkManager ,它大大简化了 fork 位?
  • 作为一个较小的样式,您可能应该使用3个arg'open'。
    #!/usr/bin/env perl
    use strict;
    use warnings;
    use Parallel::ForkManager;
    
    my $maxForks = 50;
    
    my $manager = Parallel::ForkManager->new($maxForks);
    
    while ($ciflist) {
    
        ## do something with $_ to parse.
    
        ##instead of: extractPDFByCIF($cifNumFromIndex, $acctTypeFromIndex, $startDate, $endDate);
    
        # doing SQL constructing to for the $stmt to do a DB query
        $stmt->execute();
    
        while ( $stmt->fetch() ) {
    
            # fork the copy/afp2web process into child process
            $manager->start and next;
            print "CHILDFORK: Processing child fork. PID=$$\n";
    
            # prevent child fork to destroy dbh from parent thread
            $dbh->{InactiveDestroy} = 1;
            undef $dbh;
    
            # perform the conversion as usual
            if ( $fileName =~ m/.afp/ ) {
                system("file-conversion -parameter-list");
            } elsif ( $fileName =~ m/.pdf/ ) {
                system("cp $from-file $to-file");
            } else {
                print ERRORLOG "Problem happened here\r\n";
            }
    
            # end forking
            $manager->finish;
        }
        $stmt->finish();
    
    }
    
    $manager->wait_all_children;
    
  • 关于multithreading - perl fork()似乎没有利用内核,而只有cpu,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40500013/

    相关文章:

    c - 使用 fputc 通过管道写入

    c++ - (c/c++) 试图强制 EOF 从父进程发送输入到子进程

    php - PHP线程化TCP套接字服务器

    c# - 等待一个漫长的过程,还在更新UI

    java - Executor 关闭后 ScheduledFuture.get() 仍然被阻塞

    git - 在perl中返回变量和字符串的组合

    html - 使用 cid :attachmentID in e-mail for image file used in css 的语法是什么

    java - 将 ByteArrayOutputStream 发送到 Perl 脚本,然后读取响应

    android - 如何使用线程更新进度条

    c - 在另一个子进程写入文本文件时锁定文本文件