4
18
2011
4

Perl 与 Python 3 线程机制实测比较

      计算机世界没有免费的午餐。特别地,CPU时间与内存消耗通常存在此消彼长的关系。实现某个功能,某算法可能使用更多CPU时间但占用更少内存,而另一算法可能使用更少CPU时间而占用更多内存。

      而另一种状况是,对于某种功能,某种实现占用更少内存但无法充分利用CPU时间,而另一种实现会消耗更多的内存但能更充分地利用CPU。在线程机制上,Python就属于前者,而Perl属于后者。下面通过几个简单的例子来体验一下这种差别。

      CPython 的线程机制使用了 Global Interpreter Lock 来实现,粗略的理解就是由一个解释器程序轮流来执行各个线程。

      Perl 的线程机制称为 ithread,粗略理解就是每个线程都有一个独立的解释器,也即是Perl进程的内存空间可能有多个解释器副本。

 

测试环境

CPU: AMD Phenom(tm) II X6 1055T Processor  (六核 2.8GHz)

         (也即是每个核心占总CPU时间约 17%)

RAM: 8G

OS: Fedora 15 beta (Linux 2.6.38.2-9.fc15.x86_64)

Python 3.2

Perl 5.12.3


Python 代码:

#! /usr/bin/env python3
import sys
import time
import threading

def main():
    if len(sys.argv) == 1:
        print("%s [-r] num"%sys.argv[0])
        exit(1);
    elif len(sys.argv) == 2:
        is_sleep = False
        thr_count = int(sys.argv[1])
    else:
        is_sleep = True
        thr_count = int(sys.argv[2])
    if thr_count < 1:
        thr_count = 1
    if is_sleep:
        func = dead_loop_with_sleep
    else:
        func = dead_loop
    if thr_count > 1:
        for i in range(thr_count-1):
            t = threading.Thread(target=func)
            t.start()
    func()

def dead_loop():
    while True:
        pass

def dead_loop_with_sleep():
    while True:
        time.sleep(1);

if __name__ == "__main__":
    main()

Perl 代码:

#!/usr/bin/env perl
use strict;
use warnings;
use threads;

my $is_sleep;
my $thr_count;

if (!@ARGV){
    print("$0 [-r] num\n");
    exit(1);
}
elsif (@ARGV == 1){
    $thr_count = int($ARGV[0]);
}
else {
    $is_sleep = 1;
    $thr_count = int($ARGV[1]);
}
$thr_count = 1 if $thr_count < 1;

my $func_ref = $is_sleep ? \&dead_loop_with_sleep : \&dead_loop;

if ($thr_count > 1){
    for (1..($thr_count - 1)){
        threads->create($func_ref);
    }
}

&$func_ref();

sub dead_loop{
    while(1){}
}

sub dead_loop_with_sleep{
    while(1){
        sleep(1);
    }
}

 

测试结果(内存按Pss计算):

测试形态 命令行 1 core (pl) 1 core (py) all (pl) all (py) Mem (pl) Mem (py)
单线程死循环 dead_loop 1 100% 100% 17% 17% 0.7M 8.0M
6线程死循环 dead_loop 6 近100% 不可测 近100% 17% 3.7M 10.2M
500线程带睡眠死循环 dead_loop -r 500 0% 0% 0% 0% 234.1M 29.8M

 

 

 

 

 


 

总结

      6线程死循环测试表明:Python在切换线程过程中有机会让操作系统将其安排到另一核心上运行,这样各核心的占用率大致平均。也即是,Python解释器在任何时候都只占用一个核心,因此Python占用的总CPU时间比总是 17%。Perl进程则占用了所有CPU核心的几乎所有时间,充分利用了CPU的多核心,但内存占用也几乎与线程数成正比。

 

      当500线程并行时,Python的内存占用增长率显然比线程数增加率要低得多,而Perl的内存占用依然几乎与线程数成正比。

Category: 未分类 | Tags: | Read Count: 8318
Avatar_small
ee.zsy said:
Tue, 19 Apr 2011 14:19:23 +0800

Python2.6中开始提供了multiprocessing模块,用内核模式的多进程代理代替用户模式的对线程,算是曲线解决了Global Interpreter Lock问题,性能或许能有提升吧。

Avatar_small
ee.zsy said:
Tue, 19 Apr 2011 14:20:51 +0800

额,有错字。
对线程 -> 多线程

Avatar_small
Robin Lee said:
Tue, 19 Apr 2011 18:57:08 +0800

@ee.zsy: 恭喜你!你是我这个博客的第一个回复者。


Login *


loading captcha image...
(type the code from the image)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com