python_线程、进程和协程
線程
Threading用于提供線程相關(guān)的操作,線程是應(yīng)用程序中工作的最小單元。
1 #!/usr/bin/env python 2 #coding=utf-8 3 __author__ = 'yinjia' 4 5 6 import threading,time 7 8 def show(arg): 9 time.sleep(2) 10 print('線程: ' + str(arg)) 11 12 for i in range(5): 13 t = threading.Thread(target=show,args=(i,)) 14 t.start()如上述代碼創(chuàng)建了5個(gè)線程,target指向函數(shù),arges參數(shù)傳遞數(shù)值。
- 其它方法:
- setName\getName使用方法
- ?setDaemon方法使用
后臺(tái)線程:
1 #!/usr/bin/env python 2 #coding=utf-8 3 __author__ = 'yinjia' 4 5 6 import threading,time 7 8 def run(num): 9 print("running thread %s" % str(num)) 10 time.sleep(2)#主線程執(zhí)行結(jié)束后,不會(huì)執(zhí)行以下語(yǔ)句 11 print("OK! %s" % str(num)) 12 13 for i in range(2): 14 t = threading.Thread(target=run,args=(i,)) 15 #使用setDaemon時(shí)是后臺(tái)線程 16 t.setDaemon(True) 17 t.start() 18 t.setName("MyThread_{0}".format(str(i))) 19 print(t.getName()) 20 21 22 運(yùn)行結(jié)果: 23 running thread 0 24 MyThread_0 25 running thread 1 26 MyThread_1
- ?join用法理解
當(dāng)未使用join方法時(shí)候,先執(zhí)行完主線程再根據(jù)超時(shí)決定等待子線程執(zhí)行完才能程序結(jié)束;如果使用join方法,先執(zhí)行子線程執(zhí)行完后,才開始執(zhí)行下一步主線程,此方法沒有達(dá)到并行效果。
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'yinjia' 4 5 import time,threading 6 7 def do_thread(num): 8 time.sleep(3) 9 print("this is thread %s" % str(num)) 10 11 for i in range(2): 12 t = threading.Thread(target=do_thread, args=(i,)) 13 t.start() 14 t.setName("Mythread_{0}".format(str(i))) 15 print("print in main thread: thread name:", t.getName()) 16 17 運(yùn)行效果:【#先同時(shí)執(zhí)行兩個(gè)主線程,等待3秒后再執(zhí)行兩個(gè)子線程】 18 print in main thread: thread name: Mythread_0 #主線程 19 print in main thread: thread name: Mythread_1 #主線程 20 this is thread 0 #子線程 21 this is thread 1 #子線程使用join效果如下:
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ ='yinjia' 4 5 import time,threading 6 7 def do_thread(num): 8 time.sleep(3) 9 print("this is thread %s" % str(num)) 10 11 for i in range(2): 12 t = threading.Thread(target=do_thread, args=(i,)) 13 t.start() 14 t.join() #增加join 15 t.setName("Mythread_{0}".format(str(i))) 16 print("print in main thread: thread name:", t.getName()) 17 18 19 運(yùn)行結(jié)果:【先執(zhí)行子線程,然后再執(zhí)行主線程,單一逐步執(zhí)行】 20 this is thread 0 21 print in main thread: thread name: Mythread_0 22 this is thread 1 23 print in main thread: thread name: Mythread_1- 線程鎖(Lock、RLock)
線程是共享內(nèi)存,當(dāng)多個(gè)線程對(duì)一個(gè)公共變量修改數(shù)據(jù),會(huì)導(dǎo)致線程爭(zhēng)搶問題,為了解決此問題,采用線程鎖。
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'Administrator' 4 5 import time,threading 6 7 gl_num = 0 8 lock = threading.RLock() 9 10 def Func(): 11 global gl_num 12 #加鎖 13 lock.acquire() 14 gl_num += 1 15 time.sleep(1) 16 print(gl_num) 17 #解鎖 18 lock.release() 19 20 for i in range(10): 21 t = threading.Thread(target=Func) 22 t.start()- 信號(hào)量(Semaphore)
信號(hào)量同時(shí)允許一定數(shù)量的線程更改數(shù)據(jù) ,比如廁所有3個(gè)坑,那最多只允許3個(gè)人上廁所,后面的人只能等里面有人出來(lái)了才能再進(jìn)去。
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'yinjia' 4 5 import time,threading 6 7 def run(n): 8 semaphore.acquire() 9 time.sleep(1) 10 print("run the thread: %s" % n) 11 semaphore.release() 12 13 if __name__ == '__main__': 14 num = 0 15 semaphore = threading.BoundedSemaphore(5) # 最多允許5個(gè)線程同時(shí)運(yùn)行 16 for i in range(20): 17 t = threading.Thread(target=run, args=(i,)) 18 t.start()- 事件(event)
事件用于主線程控制其他線程的執(zhí)行,事件主要提供了三個(gè)方法?set、wait、clear。
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'Administrator' 4 5 import time,threading 6 7 def run(event): 8 print("start") 9 event.wait() 10 print('END.....') 11 12 event_obj = threading.Event() 13 for i in range(2): 14 t = threading.Thread(target=run,args=(event_obj,)) 15 t.start() 16 17 event_obj.clear() 18 inp = input("input: ") 19 if inp == 'true': 20 event_obj.set() 21 22 #運(yùn)行結(jié)果: 23 start 24 start 25 input: true 26 END..... 27 END.....- 條件(Condition)
滿足條件,才能釋放N個(gè)線程。
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'Administrator' 4 5 import time,threading 6 7 def condition_func(): 8 ret = False 9 inp = input('>>>') 10 if inp == '1': 11 ret = True 12 return ret 13 14 def run(n): 15 con.acquire() 16 con.wait_for(condition_func) 17 print("run the thread: %s" %n) 18 con.release() 19 20 if __name__ == '__main__': 21 22 con = threading.Condition() 23 for i in range(10): 24 t = threading.Thread(target=run, args=(i,)) 25 t.start() 26 27 #運(yùn)行結(jié)果: 28 >>>1 29 run the thread: 0 30 >>>1 31 run the thread: 1 32 >>>1 33 run the thread: 2- 定時(shí)器
?進(jìn)程
- ?進(jìn)程數(shù)據(jù)共享
?方法一:Array
1 #!/usr/bin/env python 2 #coding=utf-8 3 __author__ = 'yinjia' 4 5 6 from multiprocessing import Process, Array, RLock 7 8 def Foo(lock,temp,i): 9 """ 10 將第0個(gè)數(shù)加100 11 """ 12 lock.acquire() 13 temp[0] = 100+i 14 for item in temp: 15 print(i,'----->',item) 16 lock.release() 17 18 lock = RLock() 19 temp = Array('i', [11, 22, 33, 44]) 20 21 for i in range(20): 22 p = Process(target=Foo,args=(lock,temp,i,)) 23 p.start()方法二:manage.dict()共享數(shù)據(jù)
1 #!/usr/bin/env python 2 #coding=utf-8 3 __author__ = 'yinjia' 4 5 from multiprocessing import Process, Manager 6 7 manage = Manager() 8 dic = manage.dict() 9 10 11 def Foo(i): 12 dic[i] = 100 + i 13 print(dic) 14 print(dic.values()) 15 16 17 for i in range(2): 18 p = Process(target=Foo, args=(i,)) 19 p.start() 20 p.join()?
- 進(jìn)程池
?進(jìn)程池方法:?
apply(func[, args[, kwds]]): 阻塞的執(zhí)行,比如創(chuàng)建一個(gè)有3個(gè)線程的線程池,當(dāng)執(zhí)行時(shí)是創(chuàng)建完一個(gè) 執(zhí)行完函數(shù)再創(chuàng)建另一個(gè),變成一個(gè)線性的執(zhí)行?
apply_async(func[, args[, kwds[, callback]]]) : 它是非阻塞執(zhí)行,同時(shí)創(chuàng)建3個(gè)線程的線程池,同時(shí)執(zhí)行,只要有一個(gè)執(zhí)行完立刻放回池子待下一個(gè)執(zhí)行,并行的執(zhí)行?
close(): 關(guān)閉pool,使其不在接受新的任務(wù)。?
terminate() : 結(jié)束工作進(jìn)程,不在處理未完成的任務(wù)。?
join() 主進(jìn)程阻塞,等待子進(jìn)程的退出, join方法要在close或terminate之后使用。
?
- 生產(chǎn)者&消費(fèi)型
產(chǎn)生數(shù)據(jù)的模塊,就形象地稱為生產(chǎn)者;而處理數(shù)據(jù)的模塊,就稱為消費(fèi)者。在生產(chǎn)者與消費(fèi)者之間在加個(gè)緩沖區(qū),我們形象的稱之為倉(cāng)庫(kù),生產(chǎn)者負(fù)責(zé)往倉(cāng)庫(kù)了進(jìn)商 品,而消費(fèi)者負(fù)責(zé)從倉(cāng)庫(kù)里拿商品,這就構(gòu)成了生產(chǎn)者消費(fèi)者模型。
1 #!/usr/bin/env python 2 #coding=utf-8 3 __author__ = 'yinjia' 4 5 6 import queue 7 import threading,time 8 9 10 message = queue.Queue(10) 11 12 13 def producer(): 14 name = threading.current_thread().getName() 15 print(name + "線程啟動(dòng)....") 16 for i in range(10): 17 time.sleep(1) 18 print('\033[45m<%s> 生產(chǎn)了 [%s]個(gè)餃子\033[0m' % (name, i)) 19 message.put(name) 20 21 22 def consumer(): 23 name = threading.current_thread().getName() 24 print(name + "線程啟動(dòng).....") 25 for i in range(10): 26 message.get() 27 print('\033[43m<%s> 吃了 [%s]個(gè)餃子\033[0m' % (name, i)) 28 29 30 if __name__ == '__main__': 31 32 p = threading.Thread(target=producer, name='東北餃子店') 33 c = threading.Thread(target=consumer, name='消費(fèi)者') 34 p.start() 35 c.start()?運(yùn)行結(jié)果:
?
協(xié)程
協(xié)程存在的意義:對(duì)于多線程應(yīng)用,CPU通過切片的方式來(lái)切換線程間的執(zhí)行,線程切換時(shí)需要耗時(shí)(保存狀態(tài),下次繼續(xù))。協(xié)程,則只使用一個(gè)線程,在一個(gè)線程中規(guī)定某個(gè)代碼塊執(zhí)行順序。
協(xié)程的適用場(chǎng)景:當(dāng)程序中存在大量不需要CPU的操作時(shí)(IO),適用于協(xié)程;
- gevent
- 遇到IO操作自動(dòng)切換
?上下文管理
1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'Administrator' 4 5 import contextlib 6 7 @contextlib.contextmanager 8 def tag(name): 9 print("<%s>" % name) 10 yield 11 print("</%s>" % name) 12 13 with tag("h1"): 14 print("foo") 15 16 #運(yùn)行結(jié)果: 17 <h1> 18 foo 19 </h1> 1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'Administrator' 4 5 import contextlib 6 7 @contextlib.contextmanager 8 def myopen(file_path,mode): 9 f = open(file_path,mode,encoding='utf-8') 10 try: 11 yield f 12 finally: 13 f.close() 14 with myopen('index.html','r') as file_obj: 15 for i in file_obj: 16 print(i)更多方法參見:https://docs.python.org/3.6/library/contextlib.html
轉(zhuǎn)載于:https://www.cnblogs.com/yinjia/p/8683146.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的python_线程、进程和协程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人工智能实战小程序之语音_前端开发
- 下一篇: 如何申请广发DIY卡?怎么查询申请进度?