python_day9线程、进程和协程
Python線程
Threading用于提供線程相關(guān)的操作,線程是應(yīng)用程序中工作的最小單元。
#!/usr/bin/env?python #?-*-?coding:utf-8?-*- import?threading import?timedef?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í)行過(guò)程中,后臺(tái)線程也在進(jìn)行,主線程執(zhí)行完畢后,后臺(tái)線程不論成功與否,均停止
? ? ? ? ? ? ? ? ? ??如果是前臺(tái)線程,主線程執(zhí)行過(guò)程中,前臺(tái)線程也在進(jìn)行,主線程執(zhí)行完畢后,等待前臺(tái)線程也執(zhí)行完成后,程序停止join ? ? ? ? ? ? ?逐個(gè)執(zhí)行每個(gè)線程,執(zhí)行完畢后繼續(xù)往下執(zhí)行,該方法使得多線程變得無(wú)意義
run ? ? ? ? ? ? ?線程被cpu調(diào)度后自動(dòng)執(zhí)行線程對(duì)象的run方法
線程鎖(Lock、RLock)
由于線程之間是進(jìn)行隨機(jī)調(diào)度,并且每個(gè)線程可能只執(zhí)行n條執(zhí)行之后,當(dāng)多個(gè)線程同時(shí)修改同一條數(shù)據(jù)時(shí)可能會(huì)出現(xiàn)臟數(shù)據(jù),所以,出現(xiàn)了線程鎖 - 同一時(shí)刻允許一個(gè)線程執(zhí)行操作。
#??未使用鎖#!/usr/bin/env?python #?-*-?coding:utf-8?-*- import?threading import?timegl_num?=?0def?show(arg):global?gl_numtime.sleep(1)gl_num?+=1print?gl_numfor?i?in?range(10):t?=?threading.Thread(target=show,?args=(i,))t.start()print?'main?thread?stop'#!/usr/bin/env?python #coding:utf-8import?threading import?timegl_num?=?0lock?=?threading.RLock()def?Func():lock.acquire()global?gl_numgl_num?+=1time.sleep(1)print?gl_numlock.release()for?i?in?range(10):t?=?threading.Thread(target=Func)t.start()信號(hào)量(Semaphore)
互斥鎖 同時(shí)只允許一個(gè)線程更改數(shù)據(jù),而Semaphore是同時(shí)允許一定數(shù)量的線程更改數(shù)據(jù) ,比如廁所有3個(gè)坑,那最多只允許3個(gè)人上廁所,后面的人只能等里面有人出來(lái)了才能再進(jìn)去。
import?threading,timedef?run(n):semaphore.acquire()time.sleep(1)print("run?the?thread:?%s"?%n)semaphore.release()if?__name__?==?'__main__':num=?0semaphore??=?threading.BoundedSemaphore(5)?#最多允許5個(gè)線程同時(shí)運(yùn)行for?i?in?range(20):t?=?threading.Thread(target=run,args=(i,))t.start()事件(event)
python線程的事件用于主線程控制其他線程的執(zhí)行,事件主要提供了三個(gè)方法?set、wait、clear。
事件處理的機(jī)制:全局定義了一個(gè)“Flag”,如果“Flag”值為 False,那么當(dāng)程序執(zhí)行 event.wait 方法時(shí)就會(huì)阻塞,如果“Flag”值為T(mén)rue,那么event.wait 方法時(shí)便不再阻塞。
clear:將“Flag”設(shè)置為False
set:將“Flag”設(shè)置為T(mén)rue
條件(Condition)
使得線程等待,只有滿足某條件時(shí),才釋放n個(gè)線程
import?threadingdef?run(n):con.acquire()con.wait()print("run?the?thread:?%s"?%n)con.release()if?__name__?==?'__main__':con?=?threading.Condition()for?i?in?range(10):t?=?threading.Thread(target=run,?args=(i,))t.start()while?True:inp?=?input('>>>')if?inp?==?'q':breakcon.acquire()con.notify(int(inp))con.release()def?condition_func():ret?=?Falseinp?=?input('>>>')if?inp?==?'1':ret?=?Truereturn?retdef?run(n):con.acquire()con.wait_for(condition_func)print("run?the?thread:?%s"?%n)con.release()if?__name__?==?'__main__':con?=?threading.Condition()for?i?in?range(10):t?=?threading.Thread(target=run,?args=(i,))t.start()Timer
定時(shí)器,指定n秒后執(zhí)行某操作
from?threading?import?Timerdef?hello():print("hello,?world")t?=?Timer(1,?hello) t.start()??#?after?1?seconds,?"hello,?world"?will?be?printedPython 進(jìn)程
from?multiprocessing?import?Process import?threading import?timedef?foo(i):print?'say?hi',ifor?i?in?range(10):p?=?Process(target=foo,args=(i,))p.start()注意:由于進(jìn)程之間的數(shù)據(jù)需要各自持有一份,所以創(chuàng)建進(jìn)程需要的非常大的開(kāi)銷(xiāo)。
進(jìn)程數(shù)據(jù)共享
進(jìn)程各自持有一份數(shù)據(jù),默認(rèn)無(wú)法共享數(shù)據(jù)
#??進(jìn)程間默認(rèn)無(wú)法數(shù)據(jù)共享#!/usr/bin/env?python #coding:utf-8from?multiprocessing?import?Process from?multiprocessing?import?Managerimport?timeli?=?[]def?foo(i):li.append(i)print?'say?hi',lifor?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+ifor?item?in?temp:print?i,'----->',itemfor?i?in?range(2):p?=?Process(target=Foo,args=(i,))p.start()#方法二:manage.dict()共享數(shù)據(jù) from?multiprocessing?import?Process,Managermanage?=?Manager() dic?=?manage.dict()def?Foo(i):dic[i]?=?100+iprint?dic.values()for?i?in?range(2):p?=?Process(target=Foo,args=(i,))p.start()p.join()#??類(lèi)型對(duì)應(yīng)表'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_doublefrom?multiprocessing?import?Process,?Queuedef?f(i,q):print(i,q.get())if?__name__?==?'__main__':q?=?Queue()q.put("h1")q.put("h2")q.put("h3")for?i?in?range(10):p?=?Process(target=f,?args=(i,q,))p.start()當(dāng)創(chuàng)建進(jìn)程時(shí)(非使用時(shí)),共享數(shù)據(jù)會(huì)被拿到子進(jìn)程中,當(dāng)進(jìn)程中執(zhí)行完畢后,再賦值給原值。
#??進(jìn)程鎖實(shí)例#!/usr/bin/env?python #?-*-?coding:utf-8?-*-from?multiprocessing?import?Process,?Array,?RLockdef?Foo(lock,temp,i):"""將第0個(gè)數(shù)加100"""lock.acquire()temp[0]?=?100+ifor?item?in?temp:print?i,'----->',itemlock.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)程池序列中沒(méi)有可供使用的進(jìn)進(jìn)程,那么程序就會(huì)等待,直到進(jìn)程池中有可用進(jìn)程為止。
進(jìn)程池中有兩個(gè)方法:
apply
apply_async
協(xié)程
線程和進(jìn)程的操作是由程序觸發(fā)系統(tǒng)接口,最后的執(zhí)行者是系統(tǒng);協(xié)程的操作則是程序員。
協(xié)程存在的意義:對(duì)于多線程應(yīng)用,CPU通過(guò)切片的方式來(lái)切換線程間的執(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?greenletdef?test1():print?12gr2.switch()print?34gr2.switch()def?test2():print?56gr1.switch()print?78gr1?=?greenlet(test1) gr2?=?greenlet(test2) gr1.switch()gevent
import?geventdef?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()??#?自己體會(huì)這句話的作用 import?gevent import?urllib2def?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/'), ])轉(zhuǎn)載于:https://blog.51cto.com/cuzihate/1861266
總結(jié)
以上是生活随笔為你收集整理的python_day9线程、进程和协程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: UML静态建模之用例图
- 下一篇: python property理解