定義:Threading用於提供線程相關的操作,線程是應用程式中工作的最小單元。 上述代碼創建了10個“前臺”線程,然後控制器就交給了CPU,CPU根據指定演算法進行調度,分片執行指令。 更多方法: 線程鎖 由於線程之間是進行隨機調度,並且每個線程可能只執行n條執行之後,CPU接著執行其他線程。所以,
Python線程
定義:Threading用於提供線程相關的操作,線程是應用程式中工作的最小單元。
#!/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
上述代碼創建了10個“前臺”線程,然後控制器就交給了CPU,CPU根據指定演算法進行調度,分片執行指令。
更多方法:
- start 線程準備就緒,等待CPU調度
- setName 為線程設置名稱
- getName 獲取線程名稱
- setDaemon 設置為後臺線程或前臺線程(預設)
如果是後臺線程,主線程執行過程中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,均停止
如果是前臺線程,主線程執行過程中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程式停止 - join 逐個執行每個線程,執行完畢後繼續往下執行,該方法使得多線程變得無意義
- run 線程被cpu調度後自動執行線程對象的run方法
線程鎖
由於線程之間是進行隨機調度,並且每個線程可能只執行n條執行之後,CPU接著執行其他線程。所以,可能出現如下問題:
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線程的事件用於主線程式控制制其他線程的執行,事件主要提供了三個方法 set、wait、clear。
事件處理的機制:全局定義了一個“Flag”,如果“Flag”值為 False,那麼當程式執行 event.wait 方法時就會阻塞,如果“Flag”值為True,那麼event.wait 方法時便不再阻塞。
- clear:將“Flag”設置為False
- set:將“Flag”設置為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 進程
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()
註意:由於進程之間的數據需要各自持有一份,所以創建進程需要的非常大的開銷。
進程數據共用
進程各自持有一份數據,預設無法共用數據
#!/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()共用數據 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
當創建進程時(非使用時),共用數據會被拿到子進程中,當進程中執行完畢後,再賦值給原值。
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process, Array, RLock def Foo(lock,temp,i): """ 將第0個數加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()
進程池
進程池內部維護一個進程式列,當使用時,則去進程池中獲取一個進程,如果進程池序列中沒有可供使用的進進程,那麼程式就會等待,直到進程池中有可用進程為止。
進程池中有兩個方法:
- 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()#進程池中進程執行完畢後再關閉,如果註釋,那麼程式直接關閉
協程
線程和進程的操作是由程式觸發系統介面,最後的執行者是系統;協程的操作則是程式員。
協程存在的意義:對於多線程應用,CPU通過切片的方式來切換線程間的執行,線程切換時需要耗時(保存狀態,下次繼續)。協程,則只使用一個線程,在一個線程中規定某個代碼塊執行順序。
協程的適用場景:當程式中存在大量不需要CPU的操作時(IO),適用於協程;
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操作自動切換:
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/'), ])