-
進程是操作系統分配內存的基本單元,進程之間的內存是相互隔離的,通過icp機制/管道通信。
一個進程可以劃分爲多個線程,線程是進程的執行單元 ,也是操作系統分配cpu的執行單元;線程啓用的越多,佔用cpu越多。使用多線程/多進程可以提升執行效率,縮短程序執行時間;改善用戶體驗。
-
python中使用多進程比多線程更好,因爲多進程相互之間是獨立的,程序執行效率更高。
進程
from multiprocessing import Process
import subprocess # subprocess子進程
import time
import os
def output():
print(os.getpid()) # 啓用多進程
while True:
print('Pong', end = '', flush=True) # flush=True關閉緩存
time.sleep(0.001)
def main():
print(os.getpid) # 打印進程號
p = Process(target=output) # 這裏傳入函數名,表示進程啓用後纔在這個進程裏面去執行函數
p.start()
while True:
print('Ping', end = '', flush=True)
time.sleep(0.001)
def main():
subprocess.call('calc') # call調用calc計算器
subprocess.call('notepad')
if __name__ == '__main__':
main()
線程
- 多線程是共享內存的,共享數據。
python不能用到cpu的多核特性,但是這不代表他的多進程、多線程是無用的。
實際開發中,多線程的程序不好寫,也不好調試,因爲cpu分配是隨機的,運行時如果有bug那麼就不知道它什麼時候回出現問題。 - 創建線程的兩種方式:
1,直接創建Thread對象並通過target參數指定線程啓動後要執行的任務。
2,繼承Thread自定義線程,通過重寫run方法指定線程啓動後執行的任務,推薦使用這種方法!
from threading import Thread # from thread是python2中使用的模塊
from time import sleep
def output():
while True:
print('Pong', end='', flush=True)
sleep(0.001)
def main():
t1 = Thread(target=output)
t1.start()
while True:
print('Ping', end='', flush=True)
sleep(0.001)
if __name__ == '__main__':
main()
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# 這裏應該使用元組,並且儘管只有一個元素,但是也要加上逗號,否則就是一個字符串
t1 = Thread(target=output, args=('Ping',))
t1.start()
t2 = Thread(target=output, args=('Pong',))
t2.start()
if __name__ == '__main__':
main()
from threading import Thread
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# daemon=True - 將線程設置爲守護線程(不值得保留的線程),其他線程/主程序如果執行完了,那麼守護線程自動結束
t1 = Thread(target=output, args=('Ping',),daemon=True)
t1.start()
t2 = Thread(target=output, args=('Pong',), daemon=True)
t2.start()
if __name__ == '__main__':
main()
多進程模擬下載文件
如果多個任務之間沒有任何的關聯(獨立子任務),而且希望利用cpu的多核特性,那麼我們推薦使用多進程,因爲任務之間沒有數據交換
import time
import random
from threading import Thread
def download(filename):
print('開始下載%s...' % filename)
delay = random.randint(5,15)
time.sleep(delay)
print('%s下載完成,用時%d秒' % (filename, delay))
# 如果要寫多線程,推薦使用這種方法
class DownloadTask(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename
# 鉤子函數(hook) / 回調函數(callback)(寫了這個方法,但是從來沒有調用它,它是讓系統啓動線程的時候自動回調這個方法)
# 寫程序時啓用線程用start,不能用run!!!
def run(self):
download(self._filename)
def main():
start = time.time()
t1 = DownloadTask('Python從入門到住院.pdf')
t1.start()
t2 = DownloadTask('Pekin Hot.avi')
t2.start()
t1.join() # join等待進程結束(然後再打印時間)
t2.join()
end = time.time()
print('總共耗費了%f秒' % (end - start))
if __name__ == '__main__':
main()