什麼是進程?
進程是指系統中正在運行的一個應用程序。進程就好比工廠的車間,它代表cpu所能處理的單個任務。任一時刻,cpu總是運行一個進程,其它進程處於非運行狀態。
一個操作系統中它肯定有多個進程,但是多個進程它是互不干擾的。同一時刻只能有一個進程在運行,我們看到的就是一個瀏覽器Chrome,它的一個進程的消息的一個模型,就是說它每個標籤頁其實是單獨開的一個進程,它就達到了一種互不干擾的,如果你正在看這個標籤頁的話,它不會影響其它標籤頁的情況,這個就是一個利用多進程的例子。
為什麼使用多進程?
Python中的多線程其實硬不是正真的多線程,如果想要充分地使用多核cpu的資源,在Python中大部分情況需要使用多進程。
Python提供了非常好用的多進程包multiprocessing,只需要定義一個函數,Python會完成其它所有事情。藉助這個包,可以輕鬆完成從單進程並發執行的轉換。
如何使用多進程實現Paramiko操作?
下面很簡單地實現一個多進程版本的paramiko連接遠程伺服器。本章是接著Python遠程連接模塊Paramiko使用這篇文章來完成多進程實現paramiko操作的。
之前我建立一個文件,叫做config.conf
[ssh]host=10.10.0.112port=22username=rootpassword=123456timeout=1.0
被封裝過的代碼如下:
import paramikoimport configparser class ParamikoClient: def __init__(self, file): self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.config = configparser.ConfigParser() self.config.read(file) def connect(self): try: self.client.connect( hostname = self.config.get('ssh','host'), port = self.config.getint('ssh','port'), username = self.config.get('ssh','username'), password = self.config.get('ssh','password'), timeout = self.config.getfloat('ssh','timeout') ) except Exception as e: print(e) try: self.client.close() except: pass def runcmd(self, cmd): stdin, stdout, stderr = self.client.exec_command(cmd) return stdout.read().decode()
單進程直接這麼使用即可:
from ParamikoClient import ParamikoClient def process(): client = ParamikoClient('config.conf') client.connect() client.runcmd('date') if __name__ == '__main__': process()
這就是在一個進程內來處理這個paramiko的操作。一個process它其實在這個main函數裡面,它就在這個進程裡面運行了,然後如果我們要用多個進程的時候,我們可以這樣設計config。
[ssh1]host=10.10.0.112port=22username=rootpassword=123456timeout=1.0 [ssh2]host=10.10.0.112port=22username=rootpassword=123456timeout=1.0 [ssh3]host=10.10.0.112port=22username=rootpassword=123456timeout=1.0
我們可以讓它有多個section,一個進程運行一個section。
首先改動ParamikoClient.py腳本,如下:
import paramikoimport configparser class ParamikoClient: def __init__(self, file, section): self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.config = configparser.ConfigParser() self.config.read(file) self.section = section def connect(self): try: self.client.connect( hostname = self.config.get(self.section,'host'), port = self.config.getint(self.section,'port'), username = self.config.get(self.section,'username'), password = self.config.get(self.section,'password'), timeout = self.config.getfloat(self.section,'timeout') ) except Exception as e: print(e) try: self.client.close() except: pass def runcmd(self, cmd): stdin, stdout, stderr = self.client.exec_command(cmd) return stdout.read().decode()
然後寫一個多進程調用腳本,如下:
from ParamikoClient import ParamikoClientfrom multiprocessing import Poolimport time def process(section): client = ParamikoClient('config.conf', section) client.connect() a = client.runcmd('date') print(a, end='') task_num = 3 if __name__ == '__main__': # single process time; start = time.time() pool = Pool() process('ssh1') process('ssh2') process('ssh3') print(time.time() - start) # multi process time; start = time.time() task_num = task_num + 1 for i in range(1, task_num): section = 'ssh'+str(i) pool.apply_async(process, args=(section, )) pool.close() pool.join() print(time.time() - start)
執行結果如下:
$ python process.py Tue Oct 24 04:29:10 EDT 2017Tue Oct 24 04:29:10 EDT 2017Tue Oct 24 04:29:10 EDT 20170.6342382431030273Tue Oct 24 04:29:11 EDT 2017Tue Oct 24 04:29:11 EDT 2017Tue Oct 24 04:29:11 EDT 20170.2790086269378662
從結果可以看到時間縮短了2/3。多進程它的一個特點,就是說它有它的並發性,就是說每一個進程互不影響它們是同是進行的。只要你的機子是多核,它就會充分利用多核的優勢來進行查詢,然後我們就看到了多進程操作,遠程機器的這麼一個優點。