簡(jiǎn)述Python中的進(jìn)程、線程、協(xié)程
進(jìn)程、線程和協(xié)程之間的關(guān)系和區(qū)別也困擾我一陣子了,最近有一些心得,寫一下。
進(jìn)程擁有自己獨(dú)立的堆和棧,既不共享堆,亦不共享?xiàng)?,進(jìn)程由操作系統(tǒng)調(diào)度。
線程擁有自己獨(dú)立的棧和共享的堆,共享堆,不共享?xiàng)?,線程亦由操作系統(tǒng)調(diào)度(標(biāo)準(zhǔn)線程是的)。
協(xié)程和線程一樣共享堆,不共享?xiàng)#瑓f(xié)程由程序員在協(xié)程的代碼里顯示調(diào)度。
進(jìn)程和其他兩個(gè)的區(qū)別還是很明顯的。
協(xié)程和線程的區(qū)別是:協(xié)程避免了無意義的調(diào)度,由此可以提高性能,但也因此,程序員必須自己承擔(dān)調(diào)度的責(zé)任,同時(shí),協(xié)程也失去了標(biāo)準(zhǔn)線程使用多CPU的能力。
Python線程
定義:Threading用于提供線程相關(guān)的操作,線程是應(yīng)用程序中工作的最小單元。
#!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time def show(arg): time.sleep(1) print 'thread'+str(arg) for i in range(10): t = threading.Thread(target=show, args=(i,)) t.start() print 'main thread stop
上述代碼創(chuàng)建了10個(gè)“前臺(tái)”線程,然后控制器就交給了CPU,CPU根據(jù)指定算法進(jìn)行調(diào)度,分片執(zhí)行指令。
更多方法:
•start 線程準(zhǔn)備就緒,等待CPU調(diào)度
•setName 為線程設(shè)置名稱
•getName 獲取線程名稱
•setDaemon 設(shè)置為后臺(tái)線程或前臺(tái)線程(默認(rèn))
如果是后臺(tái)線程,主線程執(zhí)行過程中,后臺(tái)線程也在進(jìn)行,主線程執(zhí)行完畢后,后臺(tái)線程不論成功與否,均停止
如果是前臺(tái)線程,主線程執(zhí)行過程中,前臺(tái)線程也在進(jìn)行,主線程執(zhí)行完畢后,等待前臺(tái)線程也執(zhí)行完成后,程序停止
•join 逐個(gè)執(zhí)行每個(gè)線程,執(zhí)行完畢后繼續(xù)往下執(zhí)行,該方法使得多線程變得無意義
•run 線程被cpu調(diào)度后自動(dòng)執(zhí)行線程對(duì)象的run方法
線程鎖
由于線程之間是進(jìn)行隨機(jī)調(diào)度,并且每個(gè)線程可能只執(zhí)行n條執(zhí)行之后,CPU接著執(zhí)行其他線程。所以,可能出現(xiàn)如下問題:
import threading import time gl_num = 0 def show(arg): global gl_num time.sleep(1) gl_num +=1 print gl_num for i in range(10): t = threading.Thread(target=show, args=(i,)) t.start() print 'main thread stop' import threading import time gl_num = 0 lock = threading.RLock() def Func(): lock.acquire() global gl_num gl_num +=1 time.sleep(1) print gl_num lock.release() for i in range(10): t = threading.Thread(target=Func) t.start()
event
python線程的事件用于主線程控制其他線程的執(zhí)行,事件主要提供了三個(gè)方法 set、wait、clear。
事件處理的機(jī)制:全局定義了一個(gè)“Flag”,如果“Flag”值為 False,那么當(dāng)程序執(zhí)行 event.wait 方法時(shí)就會(huì)阻塞,如果“Flag”值為True,那么event.wait 方法時(shí)便不再阻塞。
•clear:將“Flag”設(shè)置為False
•set:將“Flag”設(shè)置為True
#!/usr/bin/env python # -*- coding:utf-8 -*- import threading def do(event): print 'start' event.wait() print 'execute' event_obj = threading.Event() for i in range(10): t = threading.Thread(target=do, args=(event_obj,)) t.start() event_obj.clear() inp = raw_input('input:') if inp == 'true': event_obj.set()
Python 進(jìn)程
from multiprocessing import Process import threading import time def foo(i): print 'say hi',i for i in range(10): p = Process(target=foo,args=(i,)) p.start()
注意:由于進(jìn)程之間的數(shù)據(jù)需要各自持有一份,所以創(chuàng)建進(jìn)程需要的非常大的開銷。
進(jìn)程數(shù)據(jù)共享
進(jìn)程各自持有一份數(shù)據(jù),默認(rèn)無法共享數(shù)據(jù)
#!/usr/bin/env python #coding:utf-8 from multiprocessing import Process from multiprocessing import Manager import time li = [] def foo(i): li.append(i) print 'say hi',li for i in range(10): p = Process(target=foo,args=(i,)) p.start() print ('ending',li)
#方法一,Array
from multiprocessing import Process,Array temp = Array('i', [11,22,33,44]) def Foo(i): temp[i] = 100+i for item in temp: print i,'----->',item for i in range(2): p = Process(target=Foo,args=(i,)) p.start()
#方法二:manage.dict()共享數(shù)據(jù)
from multiprocessing import Process,Manager manage = Manager() dic = manage.dict() def Foo(i): dic[i] = 100+i print dic.values() for i in range(2): p = Process(target=Foo,args=(i,)) p.start() p.join() 'c': ctypes.c_char, 'u': ctypes.c_wchar, 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 'h': ctypes.c_short, 'H': ctypes.c_ushort, 'i': ctypes.c_int, 'I': ctypes.c_uint, 'l': ctypes.c_long, 'L': ctypes.c_ulong, 'f': ctypes.c_float, 'd': ctypes.c_double
當(dāng)創(chuàng)建進(jìn)程時(shí)(非使用時(shí)),共享數(shù)據(jù)會(huì)被拿到子進(jìn)程中,當(dāng)進(jìn)程中執(zhí)行完畢后,再賦值給原值。
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process, Array, RLock def Foo(lock,temp,i): """ 將第0個(gè)數(shù)加100 """ lock.acquire() temp[0] = 100+i for item in temp: print i,'----->',item lock.release() lock = RLock() temp = Array('i', [11, 22, 33, 44]) for i in range(20): p = Process(target=Foo,args=(lock,temp,i,)) p.start()
進(jìn)程池
進(jìn)程池內(nèi)部維護(hù)一個(gè)進(jìn)程序列,當(dāng)使用時(shí),則去進(jìn)程池中獲取一個(gè)進(jìn)程,如果進(jìn)程池序列中沒有可供使用的進(jìn)進(jìn)程,那么程序就會(huì)等待,直到進(jìn)程池中有可用進(jìn)程為止。
進(jìn)程池中有兩個(gè)方法:
•apply
•apply_async
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process,Pool import time def Foo(i): time.sleep(2) return i+100 def Bar(arg): print arg pool = Pool(5) #print pool.apply(Foo,(1,)) #print pool.apply_async(func =Foo, args=(1,)).get() for i in range(10): pool.apply_async(func=Foo, args=(i,),callback=Bar) print 'end' pool.close()
pool.join()#進(jìn)程池中進(jìn)程執(zhí)行完畢后再關(guān)閉,如果注釋,那么程序直接關(guān)閉
協(xié)程
線程和進(jìn)程的操作是由程序觸發(fā)系統(tǒng)接口,最后的執(zhí)行者是系統(tǒng);協(xié)程的操作則是程序員。
協(xié)程存在的意義:對(duì)于多線程應(yīng)用,CPU通過切片的方式來切換線程間的執(zhí)行,線程切換時(shí)需要耗時(shí)(保存狀態(tài),下次繼續(xù))。協(xié)程,則只使用一個(gè)線程,在一個(gè)線程中規(guī)定某個(gè)代碼塊執(zhí)行順序。
協(xié)程的適用場(chǎng)景:當(dāng)程序中存在大量不需要CPU的操作時(shí)(IO),適用于協(xié)程;
greenlet
#!/usr/bin/env python # -*- coding:utf-8 -*- from greenlet import greenlet def test1(): print 12 gr2.switch() print 34 gr2.switch() def test2(): print 56 gr1.switch() print 78 gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch()
gevent
import gevent def foo(): print('Running in foo') gevent.sleep(0) print('Explicit context switch to foo again') def bar(): print('Explicit context to bar') gevent.sleep(0) print('Implicit context switch back to bar') gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
遇到IO操作自動(dòng)切換:
from gevent import monkey; monkey.patch_all() import gevent import urllib2 def f(url): print('GET: %s' % url) resp = urllib2.urlopen(url) data = resp.read() print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([ gevent.spawn(f, 'https://www.python.org/'), gevent.spawn(f, 'https://www.yahoo.com/'), gevent.spawn(f, 'https://github.com/'), ])
以上所述是小編給大家介紹的Python中的進(jìn)程、線程、協(xié)程的相關(guān)知識(shí),希望對(duì)大家有所幫助!
相關(guān)文章
Python 使用Numpy對(duì)矩陣進(jìn)行轉(zhuǎn)置的方法
今天小編就為大家分享一篇Python 使用Numpy對(duì)矩陣進(jìn)行轉(zhuǎn)置的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01Python用Pillow(PIL)進(jìn)行簡(jiǎn)單的圖像操作方法
下面小編就為大家?guī)硪黄狿ython用Pillow(PIL)進(jìn)行簡(jiǎn)單的圖像操作方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07win與linux系統(tǒng)中python requests 安裝
requests是Python的一個(gè)HTTP客戶端庫,跟urllib,urllib2類似,今天我們主要來談?wù)剋in與linux系統(tǒng)中python requests的安裝方法以及使用指南2016-12-12Python實(shí)現(xiàn)的排列組合、破解密碼算法示例
這篇文章主要介紹了Python實(shí)現(xiàn)的排列組合、破解密碼算法,結(jié)合實(shí)例形式分析了Python排列組合、密碼破解相關(guān)數(shù)學(xué)運(yùn)算操作技巧,需要的朋友可以參考下2019-04-04一文帶你探索Python中的eventlet通信機(jī)制
這篇文章主要為大家詳細(xì)介紹了Python中的eventlet通信機(jī)制的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們深入了解Python有一定幫助,需要的可以參考一下2023-06-06Python機(jī)器學(xué)習(xí)NLP自然語言處理基本操作之京東評(píng)論分類
自然語言處理( Natural Language Processing, NLP)是計(jì)算機(jī)科學(xué)領(lǐng)域與人工智能領(lǐng)域中的一個(gè)重要方向。它研究能實(shí)現(xiàn)人與計(jì)算機(jī)之間用自然語言進(jìn)行有效通信的各種理論和方法2021-10-10python使用ctypes調(diào)用擴(kuò)展模塊的實(shí)例方法
在本篇文章里小編給大家整理的是一篇關(guān)于python使用ctypes調(diào)用擴(kuò)展模塊的實(shí)例方法內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。2020-01-01