一,回顧操做系統的概念python
操做系統位於底層硬件與應用軟件之間的一層git
工做方式:向下管理軟件,向上提供接口github
二,進程線程的概念redis
進程是一個資源單位,線程是一個最小的執行單位api
一個線程只能屬於一個進程,而一個進程能夠有多個線程,但至少有一個線程多線程
三,並行與併發併發
並行:
就是有多個進程能夠同時運行的叫作並行
併發:
就是在一個處理器的狀況下,切換執行,叫作併發
python沒法實現並行處理,由於全局解釋器鎖gil致使同一時刻同一進程
只能有一個線程被運行。
GIL全局解釋器鎖
可是不影響Python開多進程
多線程代碼示例
app
import threading import time ''' 程序在運行是有一個主線程,當程序開啓多線程的時候,主線程依舊會執行, 主線程執行到最後時,並無結束,而是在等待子線程的結束後主線程結束 ''' def misc(): print("聽歌") time.sleep(3) print("聽歌結束") def xieboke(): print("寫博客") time.sleep(5) print("寫博客結束") #開啓線程 t1=threading.Thread(target=misc)#t1,t2是一個線程對象 t2=threading.Thread(target=xieboke) t1.start() t2.start() print("主線程")
#開啓多線程的另外一種方式
函數
import threading import time class MyThread(threading.Thread): ''' 用類的繼承,繼承線程的方法開啓線程 ''' def __init__(self,num): ''' 繼承父類的__init__方法 ''' threading.Thread.__init__(self) self.num=num def run(self): print("running on mythread:%s"%self.num) time.sleep(3) print("end%s"%self.num) t1=MyThread(10) t2=MyThread(20) t1.start() t2.start() print("主線程")
jion的使用
t.jion方法會阻塞主進程的運行,但不會影響其餘線程的運行
setDaemon方法
-守護線程
當某個線程設置爲守護線程的時候,它會隨着主線程的結束而結束
t.setDaemon(True)
線程對象下的幾個方法:
-isAlive()檢測線程是否活動,返回值是布爾值
-getName():返回線程名
-setName():設置線程名稱
threading模塊提供的一些方法:
threading.currentTread():返回當前線程變量
threading.enumerate():返回一個包含正在運行的線程的list。
threading.activeCount():返回正在運行的線程數量
Python對於計算密集型運行比較慢,效率低;對於IO密集型效率有明顯提升
Python多線程
互斥鎖:
互斥鎖的意義就是在保護鎖內代碼同一時間只有一個線程在使用
直到代碼執行完成,解鎖後其餘線程才能執行所內代碼。
使用格式:
-lock=threading.Lock()建立一把鎖的對象
lock.acquire()#加鎖
....須要保護的執行語句
lock.release()#解鎖
死鎖與遞歸鎖
代碼示例:
ui
import threading import time muteA=threading.Lock() muteB=threading.Lock() class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): self.func1() self.func2() def func1(self): muteA.acquire() print("鎖A執行內容",MyThread.getName(self)) muteB.acquire() print("鎖B執行內容",MyThread.getName(self)) muteB.release() muteA.release() def func2(self): muteB.acquire() print("第二個函數的鎖B",MyThread.getName(self)) muteA.acquire() print("第二個函數的鎖A",MyThread.getName(self)) muteA.release() muteB.release() if __name__=="__main__": for i in range(10): my_thread=MyThread() my_thread.start()
造成死鎖的緣由在於當線程1在第二個函數中拿到鎖B向下執行須要鎖A的時候,線程2在函數1中 已經拿到的鎖A,在等待線程1釋放B。兩個線程都沒有釋放另外一個線程須要的鎖,因此就造成了死鎖。 遞歸鎖的應用 遞歸鎖未避免死鎖的產生,在鎖內實行一個引用計數,當有一把使用是計速器加一,釋放後,去除計數 到代碼在執行鎖內代碼時,若是有其餘線程搶鎖,計數若是爲零,線程能夠拿到鎖,大於零,拒絕線程拿鎖 這樣就能避免鎖的重複,也就不會產生死鎖 代碼示例: import threading import time Rlock=threading.Rlock() class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): self.func1() self.func2() def func1(self): Rlock.acquire() print("鎖A執行內容",MyThread.getName(self)) Rlock.acquire() print("鎖B執行內容",MyThread.getName(self)) Rlock.release() Rlock.release() def func2(self): Rlock.acquire() print("第二個函數的鎖B",MyThread.getName(self)) Rlock.acquire() print("第二個函數的鎖A",MyThread.getName(self)) Rlock.release() Rlock.release() if __name__=="__main__": for i in range(10): my_thread=MyThread() my_thread.start() event方法使用: event方法可讓兩個線程之間通訊,當一個線程須要另外一個線程準備數據的時候, event.wait(),阻塞程序的運行,直到另外一個線程將數據準備完成後,使用event.set() 返回一個true值,event.wait()接受到該值以後,線程開始運行。wait方法後能夠接一個超時 時間參數,規定在必定時間內阻塞,超時後運行。 import threading import time import logging logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',) def worker(event): logging.debug('Waiting for redis ready...') while not event.isSet(): logging.debug("wait.......") event.wait(3) # if flag=False阻塞,等待flag=true繼續執行 logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime()) time.sleep(1) def main(): readis_ready = threading.Event() # flag=False建立一個event對象 t1 = threading.Thread(target=worker, args=(readis_ready,), name='t1') t1.start() t2 = threading.Thread(target=worker, args=(readis_ready,), name='t2') t2.start() logging.debug('first of all, check redis server, make sure it is OK, and then trigger the redis ready event') time.sleep(6) # simulate the check progress readis_ready.set() # flag=Ture if __name__=="__main__": main() 進程multprocessing模塊 multprocessing模塊與threading模塊使用同一套api,使用方法調用方法與threading模塊同樣 代碼示例: from multiprocessing import Process import time def f(name): print("hello",name,time.ctime()) time.sleep(1) if __name__=="__main__": p_list=[] for i in range(3): p=Process(target=f,args=("alvin:%s"%i,)) p_list.append(p) p.start() 協程的應用: 協程是單線程的,不能切換。由於協程對IO操做的判斷由本身控制 import time # 能夠實現併發 def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] ←← Consuming %s...' % n) time.sleep(1) r = '200 OK' def produce(c): next(c) n = 0 while n < 5: n = n + 1 print('[PRODUCER] →→ Producing %s...' % n) cr = c.send(n) print('[PRODUCER] Consumer return: %s' % cr) c.close() if __name__=='__main__': c = consumer() produce(c) gevent模塊的使用: from gevent import monkey monkey.patch_all() import gevent from urllib import request import time def f(url): print('GET: %s' % url) resp = request.urlopen(url) data = resp.read() print('%d bytes received from %s.' % (len(data), url)) start=time.time() gevent.joinall([ gevent.spawn(f, 'https://itk.org/'), gevent.spawn(f, 'https://www.github.com/'), gevent.spawn(f, 'https://zhihu.com/'), ]) #f('https://itk.org/') #f('https://www.github.com/') #f('https://zhihu.com/') print(time.time()-start)