【Python】 多程式與多執行緒

小亮520cl發表於2018-01-19

1.多程式fork

  1. #!/usr/bin/env python
  2. #coding=utf8
  3.  
  4. from time import sleep
  5. import os
  6.  
  7. try:
  8.     pid = os.fork()
  9.     if pid == 0: ## fork一個子程式成功
  10.         sleep (30) ## 子程式程式碼
  11.     else:
  12.         parent_suite ## 父程式程式碼
  13. except OSError, e:
  14.     pass
  15.  
  16. print 'this is father ' ###父程式

執行
  1. [root@localhost /root ]# python tt2.py ####父程式立即結束
  2. this is father
  3. [root@localhost /root ]# ps -ef | grep -i python
  4. root 16837 1 0 16:02 pts/5 00:00:00 python tt2.py ###子程式在後臺執行
  5. root 16853 13419 0 16:02 pts/5 00:00:00 grep -i python



2.多執行緒thread

http://www.cnblogs.com/fnng/p/3670789.html 

3 subprocess

Python中可以執行shell命令的相關模組和函式有:

  • os.system
  • os.spawn*
  • os.popen*          --廢棄
  • popen2.*           --廢棄
  • commands.*      --廢棄,3.x中被移除

隨著Python版本的更新,過多的模組引起程式碼的複雜與冗餘,因此Python新引入了一個模組subprocess,將以上幾個模組中的功能集中到它當中,以後我們只需import這一個即可。

subprocess的目的就是啟動一個新的程式並且與之通訊。

1. call與check_call

父程式等待子程式執行命令,返回子程式執行命令的狀態碼,如果出現錯誤,不進行報錯

【這裡說的返回執行命令的狀態碼的意思是:如果我們透過一個變數 res = subprocess.call(['dir',shell=True]) 獲取的執行結果,我們能獲取到的是子程式執行命令執行結果的狀態碼,即res=0/1 執行成功或者不成功,並不代表說看不到執行結果,在Python的console介面中我們是能夠看到命令結果的,只是獲取不到。想獲取執行的返回結果,請看check_output。】

【不進行報錯解釋:如果我們執行的命令在執行時,作業系統不識別,系統會返回一個錯誤,如:abc命令不存在,這個結果會在console介面中顯示出來,但是我們的Python直譯器不會提示任何資訊,如果想讓Python直譯器也進行報錯,請看check_call】

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-

  3. import subprocess

  4. print "################## subprocess.call ###############"
  5. print u"call方法呼叫系統命令進行執行,如果出錯不報錯"
  6. subprocess.call(['dirt'],shell=True)
  7. print 'test1'
  8. subprocess.check_call(['dirt'],shell=True)
  9. print 'test2'
  10. ~
  [root@iZ2ze66bhrbxkc31nljgjnZ scripts]# python sub.py 
################## subprocess.call ###############
call方法呼叫系統命令進行執行,如果出錯不報錯
/bin/sh: dirt: command not found
test1                                       ----call 不進行報錯,程式繼續
/bin/sh: dirt: command not found
Traceback (most recent call last):
  File "sub.py", line 10, in
    subprocess.check_call(['dirt'],shell=True)
  File "/usr/lib64/python2.6/subprocess.py", line 505, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['dirt']' returned non-zero exit status 127   ---check_call報錯,程式中斷



Popen

  實際上,subprocess模組中只定義了一個類: Popen。上面的幾個函式都是基於Popen()的封裝(wrapper)。從Python2.4開始使用Popen來建立程式,用於連線到子程式的標準輸入/輸出/錯誤中去,還可以得到子程式的返回值。這些封裝的目的在於讓我們容易使用子程式。當我們想要更個性化我們的需求的時候,就要轉向Popen類,該類生成的物件用來代表子程式。

建構函式如下:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

與上面的封裝不同,Popen物件建立後,主程式不會自動等待子程式完成。我們必須呼叫物件的wait()方法,父程式才會等待 (也就是阻塞block)。

1.不等待子程式
  1. #!/usr/bin/env python
  2. import subprocess

  3. child = subprocess.Popen(['ping','-c','4',''])
  4. print 'hello'

 [root@iZ2ze66bhrbxkc31nljgjnZ scripts]# python pop.py 
hello                                                                                                 ---父程式與子程式一起開始執行
[root@iZ2ze66bhrbxkc31nljgjnZ scripts]# PING (220.181.111.188) 56(84) bytes of data.
64 bytes from 220.181.111.188: icmp_seq=1 ttl=53 time=4.81 ms
64 bytes from 220.181.111.188: icmp_seq=2 ttl=53 time=4.75 ms
64 bytes from 220.181.111.188: icmp_seq=3 ttl=53 time=4.80 ms
64 bytes from 220.181.111.188: icmp_seq=4 ttl=53 time=4.88 ms

2.等待子程式
  1. #!/usr/bin/env python
  2. import subprocess

  3. child = subprocess.Popen(['ping','-c','4','www.baidu.com'])
  4. child.wait()
  5. print 'hello'


  6. [root@iZ2ze66bhrbxkc31nljgjnZ scripts]# python pop.py
  7. PING www.a.shifen.com (220.181.112.244) 56(84) bytes of data.
  8. 64 bytes from 220.181.112.244: icmp_seq=1 ttl=53 time=4.55 ms
  9. 64 bytes from 220.181.112.244: icmp_seq=2 ttl=53 time=4.60 ms
  10. 64 bytes from 220.181.112.244: icmp_seq=3 ttl=53 time=4.61 ms
  11. 64 bytes from 220.181.112.244: icmp_seq=4 ttl=53 time=4.58 ms

  12. --- www.a.shifen.com ping statistics ---
  13. 4 packets transmitted, 4 received, 0% packet loss, time 3006ms
  14. rtt min/avg/max/mdev = 4.559/4.591/4.615/0.022 ms
  15. hello
  

看出Python執行print操作是在child子程式操作完成以後才進行的。

此外,你還可以在父程式中對子程式進行其它操作,比如我們上面例子中的child物件:

child.poll() # 檢查子程式狀態 
child.kill() # 終止子程式 
child.send_signal() # 向子程式傳送訊號
child.terminate() # 終止子程式
ps: 子程式的PID儲存在child.pid



子程式的標準輸入、標準輸出和標準錯誤如下屬性分別表示:

child.stdin | child.stdout | child.stderr

我們還可以在Popen()建立子程式的時候改變標準輸入、標準輸出和標準錯誤,並可以利用subprocess.PIPE將多個子程式的輸入和輸出連線在一起,構成管道(pipe),如下2個例子:

例1 
#!/usr/bin/env python import subprocess

child = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE)    #將標準輸出定向輸出到subprocess.PIPE 
print child.stdout.read()                                           #使用 child.communicate()  也可

輸出結果:

[root@localhost script]# python sub.py  
total 12-rw-r--r--. 1 root root  36 Jan 23 07:38 analyse.sh
-rw-r--r--. 1 root root 446 Jan 25 19:35 sub.py

例2 
#!/usr/bin/env python 
import subprocess
child1 = subprocess.Popen(['cat','/etc/passwd'],stdout=subprocess.PIPE)
child2 = subprocess.Popen(['grep','root'],stdin=child1.stdout,stdout=subprocess.PIPE) 
print child2.communicate()

輸出結果為

('root:x:0:0:root:/root:/bin/bash\n, None)

subprocess.PIPE實際上為文字流提供一個快取區。child1的stdout將文字輸出到快取區,隨後child2的stdin從該PIPE中將文字讀取走。child2的輸出文字也被存放在PIPE中,直到communicate()方法從PIPE中讀取出PIPE中的文字。
注意:communicate()是Popen物件的一個方法,該方法會阻塞父程式,直到子程式完成

子程式命令解釋

  在上面的例子中我們建立子程式時,全部是呼叫Python進行解釋,但Python並沒有將所有命令全部解釋,當Python不能進行解釋時,就緒要呼叫系統來進行執行。


#!/usr/bin/env python 
import subprocess

subprocess.Popen(['ls','-l'])

subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True)

結果

>>> subprocess.Popen(['ifconfig|grep 127.0.0.1'],shell=True)
>>>           inet addr:127.0.0.1  Mask:255.0.0.0


multiprocessing模組
  1. http://blog.csdn.net/myjiayan/article/details/46596161


參考:
Python的多執行緒threading不能併發





來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29096438/viewspace-2150311/,如需轉載,請註明出處,否則將追究法律責任。

相關文章