python_day9线程、进程和协程
Python線程
Threading用于提供線程相關的操作,線程是應用程序中工作的最小單元。
#!/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'上述代碼創建了10個“前臺”線程,然后控制器就交給了CPU,CPU根據指定算法進行調度,分片執行指令。
更多方法:
start ? ? ? ? ? ?線程準備就緒,等待CPU調度
setName ? ? ?為線程設置名稱
getName ? ? ?獲取線程名稱
setDaemon ? 設置為后臺線程或前臺線程(默認)
? ? ? ? ? ? ? ? ? ?如果是后臺線程,主線程執行過程中,后臺線程也在進行,主線程執行完畢后,后臺線程不論成功與否,均停止
? ? ? ? ? ? ? ? ? ??如果是前臺線程,主線程執行過程中,前臺線程也在進行,主線程執行完畢后,等待前臺線程也執行完成后,程序停止join ? ? ? ? ? ? ?逐個執行每個線程,執行完畢后繼續往下執行,該方法使得多線程變得無意義
run ? ? ? ? ? ? ?線程被cpu調度后自動執行線程對象的run方法
線程鎖(Lock、RLock)
由于線程之間是進行隨機調度,并且每個線程可能只執行n條執行之后,當多個線程同時修改同一條數據時可能會出現臟數據,所以,出現了線程鎖 - 同一時刻允許一個線程執行操作。
#??未使用鎖#!/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()信號量(Semaphore)
互斥鎖 同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據 ,比如廁所有3個坑,那最多只允許3個人上廁所,后面的人只能等里面有人出來了才能再進去。
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個線程同時運行for?i?in?range(20):t?=?threading.Thread(target=run,args=(i,))t.start()事件(event)
python線程的事件用于主線程控制其他線程的執行,事件主要提供了三個方法?set、wait、clear。
事件處理的機制:全局定義了一個“Flag”,如果“Flag”值為 False,那么當程序執行 event.wait 方法時就會阻塞,如果“Flag”值為True,那么event.wait 方法時便不再阻塞。
clear:將“Flag”設置為False
set:將“Flag”設置為True
條件(Condition)
使得線程等待,只有滿足某條件時,才釋放n個線程
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
定時器,指定n秒后執行某操作
from?threading?import?Timerdef?hello():print("hello,?world")t?=?Timer(1,?hello) t.start()??#?after?1?seconds,?"hello,?world"?will?be?printedPython 進程
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()注意:由于進程之間的數據需要各自持有一份,所以創建進程需要的非常大的開銷。
進程數據共享
進程各自持有一份數據,默認無法共享數據
#??進程間默認無法數據共享#!/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()共享數據 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()#??類型對應表'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()當創建進程時(非使用時),共享數據會被拿到子進程中,當進程中執行完畢后,再賦值給原值。
#??進程鎖實例#!/usr/bin/env?python #?-*-?coding:utf-8?-*-from?multiprocessing?import?Process,?Array,?RLockdef?Foo(lock,temp,i):"""將第0個數加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()進程池
進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,如果進程池序列中沒有可供使用的進進程,那么程序就會等待,直到進程池中有可用進程為止。
進程池中有兩個方法:
apply
apply_async
協程
線程和進程的操作是由程序觸發系統接口,最后的執行者是系統;協程的操作則是程序員。
協程存在的意義:對于多線程應用,CPU通過切片的方式來切換線程間的執行,線程切換時需要耗時(保存狀態,下次繼續)。協程,則只使用一個線程,在一個線程中規定某個代碼塊執行順序。
協程的適用場景:當程序中存在大量不需要CPU的操作時(IO),適用于協程;
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操作自動切換:
from?gevent?import?monkey;?monkey.patch_all()??#?自己體會這句話的作用 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/'), ])轉載于:https://blog.51cto.com/cuzihate/1861266
總結
以上是生活随笔為你收集整理的python_day9线程、进程和协程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UML静态建模之用例图
- 下一篇: IO之流程与buffer概览