進(jìn)程是什么?
進(jìn)程就是一個(gè)程序在一個(gè)數(shù)據(jù)集上的一次動(dòng)態(tài)執(zhí)行過程。進(jìn)程一般由程序、數(shù)據(jù)集、進(jìn)程控制塊三部分組成。我們編寫的程序用來描述進(jìn)程要完成哪些功能以及如何完成;數(shù)據(jù)集則是程序在執(zhí)行過程中所需要使用的資源;進(jìn)程控制塊用來記錄進(jìn)程的外部特征,描述進(jìn)程的執(zhí)行變化過程,系統(tǒng)可以利用它來控制和管理進(jìn)程,它是系統(tǒng)感知進(jìn)程存在的唯一標(biāo)志。
線程是什么?
線程也叫輕量級(jí)進(jìn)程,它是一個(gè)基本的CPU執(zhí)行單元,也是程序執(zhí)行過程中的最小單元,由線程ID、程序計(jì)數(shù)器、寄存器集合和堆棧共同組成。線程的引入減小了程序并發(fā)執(zhí)行時(shí)的開銷,提高了操作系統(tǒng)的并發(fā)性能。線程沒有自己的系統(tǒng)資源。
進(jìn)程和線程的區(qū)別
進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。或者說進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。
線程則是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。
進(jìn)程和線程的關(guān)系:
(1)一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程,但至少有一個(gè)線程。
(2)資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。
(3)CPU分給線程,即真正在CPU上運(yùn)行的是線程。
![](/d/20211017/85dca6c9473b9a01623f77e5b1e8f104.gif)
并行和并發(fā)
并行處理(Parallel Processing)是計(jì)算機(jī)系統(tǒng)中能同時(shí)執(zhí)行兩個(gè)或者更多個(gè)處理的一種計(jì)算方法。并行處理可同時(shí)工作于同一程序的不同方面,并行處理的主要目的是節(jié)省大型和復(fù)雜問題的解決時(shí)間。
并發(fā)處理(concurrency Processing)是指一個(gè)時(shí)間段中有幾個(gè)程序都處于已經(jīng)啟動(dòng)運(yùn)行到運(yùn)行完畢之間,而且這幾個(gè)程序都是在同一處理機(jī)(CPU)上運(yùn)行,但任意時(shí)刻點(diǎn)上只有一個(gè)程序在處理機(jī)(CPU)上運(yùn)行
![](/d/20211017/9d27a9de15bf6a38225e8a256fd7d2da.gif)
同步和異步
同步就是指一個(gè)進(jìn)程在執(zhí)行某個(gè)請(qǐng)求的時(shí)候,若該請(qǐng)求需要一段時(shí)間才能返回信息,那么這個(gè)進(jìn)程將會(huì)一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去;
異步是指進(jìn)程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作,不管其他進(jìn)程的狀態(tài)。當(dāng)有消息返回時(shí)系統(tǒng)會(huì)通知進(jìn)程進(jìn)行處理,這樣可以提高執(zhí)行的效率。
舉個(gè)例子,打電話時(shí)就是同步通信,發(fā)短息時(shí)就是異步通信。
單例執(zhí)行
from random import randint
from time import time, sleep
def download_task(filename):
print('開始下載%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def main():
start = time()
download_task('Python入門.pdf')
download_task('av.avi')
end = time()
print('總共耗費(fèi)了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()
運(yùn)行是順序執(zhí)行,所以耗時(shí)是多個(gè)進(jìn)程的時(shí)間總和
![](/d/20211017/8e9e3c94782805f3c212ff4616757475.gif)
因?yàn)槭菃芜M(jìn)程任務(wù),所有任務(wù)都是排隊(duì)進(jìn)行所以這樣執(zhí)行效率非常的低。我們來添加多進(jìn)程模式進(jìn)行多進(jìn)程同時(shí)執(zhí)行,這樣一個(gè)進(jìn)程執(zhí)行時(shí),另一個(gè)進(jìn)程無需等待,執(zhí)行時(shí)間將大大縮短。
多進(jìn)程
from random import randint
from time import time, sleep
from multiprocessing import Process
from os import getpid
def download_task(filename):
print('啟動(dòng)下載進(jìn)程,進(jìn)程號(hào):[%d]'%getpid())
print('開始下載%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def main():
start = time()
p1 = Process(target=download_task,args=('python入門.pdf',))
p2 = Process(target=download_task,args=('av.avi',))
p1.start()
p2.start()
p1.join()
p2.join()
# download_task('Python入門.pdf')
# download_task('av.avi')
end = time()
print('總共耗費(fèi)了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()
多個(gè)進(jìn)程并排執(zhí)行,總耗時(shí)就是最長(zhǎng)耗時(shí)的那個(gè)進(jìn)程的時(shí)間。
![](/d/20211017/8a8e449282f403f5cf423623a6c9316b.gif)
大致的執(zhí)行流程如下圖
![](/d/20211017/7abecdc75ca3a4ee41129c9987c6df2c.gif)
多進(jìn)程的特點(diǎn)是相互獨(dú)立,不會(huì)共享全局變量,即在一個(gè)進(jìn)程中對(duì)全局變量修改過后,不會(huì)影響另一個(gè)進(jìn)程中的全局變量。
進(jìn)程間通信
from random import randint
from time import time,sleep
from multiprocessing import Process
from os import getpid
time_to_download = 3
def download_task(filename):
global time_to_download
time_to_download += 1
print('啟動(dòng)下載進(jìn)程,進(jìn)程號(hào):[%d]'%getpid())
print('開始下載%s...' % filename)
sleep(time_to_download)
print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def download_task2(filename):
global time_to_download
print('啟動(dòng)下載進(jìn)程,進(jìn)程號(hào):[%d]'%getpid())
print('開始下載%s...' % filename)
sleep(time_to_download)
print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def main():
start = time()
p1 = Process(target=download_task,args=('python入門.pdf',))
p2 = Process(target=download_task2,args=('av.avi',))
p1.start()
p2.start()
p1.join()
p2.join()
end = time()
print('總共耗費(fèi)了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()
從執(zhí)行結(jié)果可以看出,兩個(gè)進(jìn)程間的全局變量無法共享,所以它們是相互獨(dú)立的
![](/d/20211017/03bb962c88ac05c253673a47365bbbc8.gif)
當(dāng)然多進(jìn)程也是可以進(jìn)行通過一些方法進(jìn)行數(shù)據(jù)共享的??梢允褂胢ultiprocessing模塊的Queue實(shí)現(xiàn)多進(jìn)程之間的數(shù)據(jù)傳遞,Queue本身是一個(gè)消息列隊(duì)程序。
這里介紹Queue的常用進(jìn)程通信的兩種方法:
put 方法用以插入數(shù)據(jù)到隊(duì)列中, put 方法還有兩個(gè)可選參數(shù): blocked 和 timeout。如果 blocked 為 True(默認(rèn)值),并且 timeout 為正值,該方法會(huì)阻塞 timeout 指定的時(shí)間,直到該隊(duì)列有剩余的空間。如果超時(shí),會(huì)拋出 Queue.full 異常。如果 blocked 為 False,但該 Queue 已滿,會(huì)立即拋出 Queue.full 異常。
get 方法可以從隊(duì)列讀取并且刪除一個(gè)元素。同樣, get 方法有兩個(gè)可選參數(shù): blocked和 timeout。如果 blocked 為 True(默認(rèn)值),并且 timeout 為正值,那么在等待時(shí)間內(nèi)沒有取到任何元素,會(huì)拋出 Queue.Empty 異常。如果 blocked 為 False,有兩種情況存在,如果Queue 有一個(gè)值可用,則立即返回該值,否則,如果隊(duì)列為空,則立即拋出Queue.Empty 異常。
Queue 隊(duì)列實(shí)現(xiàn)進(jìn)程間通信
from random import randint
from time import time,sleep
from multiprocessing import Process
import multiprocessing
from os import getpid
time_to_download = 3
def write(q):
for i in ['python入門','av.avi','java入門']:
q.put(i)
print('啟動(dòng)寫入進(jìn)程,進(jìn)程號(hào):[%d]'%getpid())
print('開始寫入%s...' % i)
sleep(time_to_download)
def read(q):
while True:
if not q.empty():
print('啟動(dòng)讀取進(jìn)程,進(jìn)程號(hào):[%d]'%getpid())
print('開始讀取%s...' % q.get())
sleep(time_to_download)
else:
break
def main():
q = multiprocessing.Queue()
p1 = Process(target=write,args=(q,))
p2 = Process(target=read,args=(q,))
p1.start()
p1.join()
p2.start()
p2.join()
if __name__ == '__main__':
main()
上一個(gè)進(jìn)程寫入的數(shù)據(jù)通過Queue隊(duì)列共享給了下一個(gè)進(jìn)程,然后下一個(gè)進(jìn)程可以直接進(jìn)行使用,這樣就完成了多進(jìn)程間的數(shù)據(jù)共享。
![](/d/20211017/e812c747fbe8478c34bf5d523a2d6061.gif)
進(jìn)程池
Pool類可以提供指定數(shù)量的進(jìn)程供用戶調(diào)用,當(dāng)有新的請(qǐng)求提交到Pool中時(shí),如果池還沒有滿,就會(huì)創(chuàng)建一個(gè)新的進(jìn)程來執(zhí)行請(qǐng)求。如果池滿,請(qǐng)求就會(huì)告知先等待,直到池中有進(jìn)程結(jié)束,才會(huì)創(chuàng)建新的進(jìn)程來執(zhí)行這些請(qǐng)求。
進(jìn)程池中常見三個(gè)方法:
◆apply:串行
◆apply_async:并行
◆map
多線程
from random import randint
from time import time, sleep
from threading import Thread
from os import getpid
def download_task(filename):
print('啟動(dòng)下載進(jìn)程,進(jìn)程號(hào):[%d]' % getpid())
print('開始下載%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def main():
start = time()
p1 = Thread(target=download_task, args=('python入門.pdf',))
p2 = Thread(target=download_task, args=('av.avi',))
p1.start()
p2.start()
p1.join()
p2.join()
end = time()
print('總共耗費(fèi)了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()
多線程執(zhí)行因?yàn)镚IL鎖的存在,實(shí)際上執(zhí)行是進(jìn)行單線程,即一次只執(zhí)行一個(gè)線程,然后在切換其他的線程進(jìn)行執(zhí)行,因?yàn)槠渲星袚Q的時(shí)間非常的短,所以看上去依然像是多線程一起執(zhí)行。
![](/d/20211017/2e56890de8cd0acf8e939fa60b70a5e3.gif)
通過繼承Thread類的方式來創(chuàng)建自定義的線程類,然后再創(chuàng)建線程對(duì)象并啟動(dòng)線程
from random import randint
from threading import Thread
from time import time, sleep
class DownloadTask(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename
def run(self):
print('開始下載%s...'% self._filename)
time_to_download = randint(5,10)
sleep(time_to_download)
print('%s下載完成!耗費(fèi)了%d秒' %(self._filename, time_to_download))
def main():
start = time()
t1 = DownloadTask('python入門')
t2 = DownloadTask('av.avi')
t1.start()
t2.start()
t1.join()
t2.join()
end = time()
print('共耗費(fèi)了%.2f秒'%(end - start))
if __name__ == '__main__':
main()
多線程使用類還是函數(shù)執(zhí)行的結(jié)果完全一致,具體怎么使用可以結(jié)合自己的使用場(chǎng)景。
![](/d/20211017/84ea8b615aa672de547070df4bd16ff1.gif)
到此這篇關(guān)于詳解Python中的進(jìn)程和線程的文章就介紹到這了,更多相關(guān)Python進(jìn)程和線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Python多線程與多進(jìn)程相關(guān)知識(shí)總結(jié)
- Python多進(jìn)程與多線程的使用場(chǎng)景詳解
- Python之多進(jìn)程與多線程的使用
- Python 多進(jìn)程、多線程效率對(duì)比
- python中線程和進(jìn)程有何區(qū)別
- python 在threading中如何處理主進(jìn)程和子線程的關(guān)系
- Python隊(duì)列、進(jìn)程間通信、線程案例