python 多進程使用總結,python進程總結

來源:互聯網
上載者:User

python 多進程使用總結,python進程總結

  python中的多進程主要使用到 multiprocessing 這個庫。這個庫在使用 multiprocessing.Manager().Queue時會出問題,建議大家升級到高版本python,如2.7.11,可具體參考《python版本升級》。

  python使用線程池可參考《python線程池實現》

一、多進程使用

1、linux下可使用 fork 函數

#!/bin/env pythonimport osprint 'Process (%s) start...' % os.getpid()pid = os.fork()if pid==0:    print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())    os._exit(1)else:    print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)

輸出 

Process (22246) start...I (22246) just created a child process (22247).I am child process (22247) and my parent is 22246.

2、使用 multiprocessing

#!/bin/env pythonfrom multiprocessing import Processimport osimport timedef run_proc(name):    time.sleep(3)    print 'Run child process %s (%s)...' % (name, os.getpid())if __name__=='__main__':    print 'Parent process %s.' % os.getpid()    processes = list()    for i in range(5):        p = Process(target=run_proc, args=('test',))        print 'Process will start.'        p.start()        processes.append(p)        for p in processes:        p.join()    print 'Process end.'

輸出

Parent process 38140.Process will start.Process will start.Process will start.Process will start.Process will start.Run child process test (38141)...Run child process test (38142)...Run child process test (38143)...Run child process test (38145)...Run child process test (38144)...Process end.real    0m3.028suser    0m0.021ssys     0m0.004s

 

二、進程池

1、使用 multiprocessing.Pool 非阻塞

#!/bin/env pythonimport multiprocessingimport timedef func(msg):    print "msg:", msg    time.sleep(3)    print "end"if __name__ == "__main__":    pool = multiprocessing.Pool(processes = 3)    for i in xrange(3):        msg = "hello %d" %(i)        pool.apply_async(func, (msg, ))    print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"    pool.close()    pool.join()    # behind close() or terminate()    print "Sub-process(es) done."

運行結果

Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~msg: hello 0msg: hello 1msg: hello 2endendendSub-process(es) done.real    0m3.493suser    0m0.056ssys     0m0.022s

2、使用 multiprocessing.Pool 阻塞版本

#!/bin/env pythonimport multiprocessingimport timedef func(msg):    print "msg:", msg    time.sleep(3)    print "end"if __name__ == "__main__":    pool = multiprocessing.Pool(processes = 3)    for i in xrange(3):        msg = "hello %d" %(i)        pool.apply(func, (msg, ))          print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"    pool.close()    pool.join()    # behind close() or terminate()    print "Sub-process(es) done."

運行結果

msg: hello 0endmsg: hello 1endmsg: hello 2endMark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~Sub-process(es) done.real    0m9.061suser    0m0.036ssys     0m0.019s

區別主要是 apply_async和 apply函數,前者是非阻塞的,後者是阻塞。可以看出已耗用時間相差的倍數正是進程池數量

3、使用 multiprocessing.Pool 並關注結果

import multiprocessingimport timedef func(msg):    print "msg:", msg    time.sleep(3)    print "end"    return "done" + msgif __name__ == "__main__":    pool = multiprocessing.Pool(processes=4)    result = []    for i in xrange(3):        msg = "hello %d" %(i)        result.append(pool.apply_async(func, (msg, )))    pool.close()    pool.join()    for res in result:        print ":::", res.get()    print "Sub-process(es) done."

運行結果

msg: hello 0msg: hello 1msg: hello 2endendend::: donehello 0::: donehello 1::: donehello 2Sub-process(es) done.real    0m3.526suser    0m0.054ssys     0m0.024s

4、在類中使用 multiprocessing.Pool

類中使用進程池會一般會出現錯誤

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed

這個提示是因為 multiprocessing.Pool中使用了Queue通訊,所有進入隊列的資料必須可序列化(picklable),包括自訂類執行個體等。如下:

#!/bin/env pythonimport multiprocessingclass SomeClass(object):    def __init__(self):        pass    def f(self, x):        return x*x    def go(self):        pool = multiprocessing.Pool(processes=4)        #result = pool.apply_async(self.f, [10])             #print result.get(timeout=1)                   print pool.map(self.f, range(10))SomeClass().go()

運行提示

Traceback (most recent call last):  File "4.py", line 18, in <module>    SomeClass().go()  File "4.py", line 16, in go    print pool.map(self.f, range(10))  File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 251, in map    return self.map_async(func, iterable, chunksize).get()  File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 567, in get    raise self._valuecPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed

解決如下:(1)

#!/bin/env pythonimport multiprocessingdef func(x):    return x*xclass SomeClass(object):    def __init__(self,func):        self.f = func    def go(self):        pool = multiprocessing.Pool(processes=4)        #result = pool.apply_async(self.f, [10])        #print result.get(timeout=1)        print pool.map(self.f, range(10))SomeClass(func).go()

輸出結果:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

(2)一般情況下我們如果在類中寫好了處理邏輯,想要儘可能減少代碼變動則可以使用下面方法

#!/bin/env pythonimport multiprocessingclass SomeClass(object):    def __init__(self):        pass    def f(self, x):        return x*x    def go(self):        result = list()        pool = multiprocessing.Pool(processes=4)        for i in range(10):            result.append(pool.apply_async(func, [self, i]))        pool.close()        pool.join()        for res in result:            print res.get(timeout=1)   def func(client, x):    return client.f(x)SomeClass().go()

輸出結果:

0149162536496481

使用(2)的解決方案需要注意,如果SomeClass執行個體中有包含任何不可序列化的資料則會一直報錯,一般是到res.get()報錯,這時候你就要重新查看代碼是否有不可序列化的變數了。如果有的話可以更改成全域變數解決。

 

三、多進程中使用線程池

有一種情景下需要使用到多進程和多線程:在CPU密集型的情況下一個ip的處理速度是0.04秒前後,單線程啟動並執行時間大概是3m32s,單個CPU使用率100%;使用進程池(size=10)時間大概是6m50s,其中只有1個進程的CPU使用率達到90%,其他均是在30%左右;使用線程池(size=10)時間大概是4m39s,單個CPU使用率100%

可以看出使用多進程在這時候並不佔優勢,反而更慢。因為進程間的切換消耗了大部分資源和時間,而一個ip只需要0.04秒。而使用線程池由於只能利用單核CPU,則再怎麼加大線程數量都沒法提升速度,所以這時候應該使用多進程加多線程結合。

def run(self):    self.getData()    ipNums = len(self.ipInfo)    step = ipNums / multiprocessing.cpu_count()    ipList = list()    i = 0    j = 1    processList = list()    for ip in self.ipInfo:        ipList.append(ip)        i += 1        if i == step * j or i == ipNums:            j += 1            def innerRun():                wm = Pool.ThreadPool(CONF.POOL_SIZE)                for myIp in ipList:                    wm.addJob(self.handleOne, myIp)                wm.waitForComplete()            process = multiprocessing.Process(target=innerRun)            process.start()            processList.append(process)            ipList = list()    for process in processList:        process.join()

機器有8個CPU,則使用8個進程加線程池,速度提升到35s,8個CPU的利用率均在50%左右,機器平均CPU75%左右。

 

四、多處理序間通訊

個人使用的比較多的是Manager,其他特別是分布式多進程可學習 廖雪峰官方網站 http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832973658c780d8bfa4c6406f83b2b3097aed5df6000

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.