線 程
併發: 任務數大於cpu的核數叫併發,多個任務交替執行, 併發看起來是一塊兒運行實際上是一個假象。
並行: 任務數小於或者等於cpu的核數並行,並行才能真正意義上多個任務一塊兒運行
1.import threading:調用功能可建立線程
2.threading.Thread(target=show_info, name="mythread",args = () ,kwargs={}):建立線程
2.1 group: 線程組,默認值是None,目前只能使用None值
2.2 target: 執行目標的函數
2.3 name: 線程名, 默認起名字相似與: Thread-1, ....
2.4 args:以元組的方式給函數傳參
2.5 kwargs: 以字典的方式給函數傳參
3.threading.current_thread():擴展: -獲取當前代碼執行的線程對象
4.threading.enumerate():獲取當前程序活動線程的列表
5.子線程.setDaemon(True):表示守住主線程, 主線程退出子線程直接銷燬再也不執行代碼
6.建立自定義線程就是建立一個類,再建立一個對象,而後對象.start()
7.子線程.join():讓主線程等待寫入線程執行完成之後程序再退出,線程同步,按照預約的順序去執行代碼,一個任務執行完成之後另一個任務才能執行
8.lock = threading.Lock():建立鎖
8.1 lock.acquire():上鎖
8.2 lock.release():釋放鎖
8.3 互斥鎖
8.3.1 保證同一時刻只有一個線程去執行代碼,其它線程沒有搶到鎖會等待
8.3.2 提示:加上互斥鎖,那個線程搶到鎖咱們絕對不了由於,線程執行是無序
8.3.3 注意點: 線程同步和加上互斥鎖把多任務瞬間該成單任務,性能會降低python
進 程
1. 進程:通俗理解一個運行起來的程序或者軟件叫作進程
1.1 每次啓動一個進程都想操做系統索要運行資源,進程是操做系統資源分配的基本單位
1.2 默認狀況下啓動一個進程默認只有一條線程,這個線程主線程, 線程是依附在進程裏面的,沒程序員
有進程就沒有線程,進程能夠有多個線程
1.3 如何理解進程:能夠把進程想成公司,公司會給員工提供辦公資源(辦公電腦,辦公桌椅等資安全
源), 真正幹活的是員工, 公司比如進程,員工線程
2. 進程和線程的對比
2.1 進程: 每次啓動一個進程都須要向操做系統索要運行資源,進程是操做系統資源分配的基本單網絡
位
2.2 線程: 執行代碼的分支,線程是cpu調度的基本單位, 線程是依附在進程裏面的,沒有進程就多線程
沒有線程,默認一個進程只有一個線程,可是能夠開闢多個線程
2.3 進程不共享全局變量, 線程共享全局變量可是要注意資源競爭數據錯誤的問題, 可使用線併發
程同步或者互斥鎖
2.4 多進程開發比單進程多線程開發穩定性要強, 由於某個進程死了不會影響其它進程的運行,但app
是單進程多線程開發,若是這個進程死了,那麼進程中的全部線程都不能再運行了
2.5 多進程開發比單進程開發資源要分配的多,多線程能夠利用進程中的資源,可是每次啓動一個框架
進程都須要向操做系統索要運行資源
3. import multiprocessing:調用功能可建立進程
4. 子線程.pid:擴展-獲取當前進程的編號
5. multiprocessing.Process(group=None, target=show_info, name="myprocess", args=("小明", 20)):建立子進程
5.1 group:進程組,默認值是None,目前只能使用None不能設置其它參數
5.2 target: 執行目標函數
5.3 name: 進程名稱,默認的格式: Process-1,....
5.4 args: 以元組方式傳參
5.5 kwargs: 以字典方式傳參
6. 子進程.start():啓動子進程,執行對應的任務
7. 子進程.pid 和 os.getpid():都是獲取子進程編號
8. os.getppid():獲取父進程(主進程)編號
9. os.kill(os.getpid(), 9):# 擴展-根據進程編號殺死對應的進程,os.getpid()進程編號,9表示強制殺死
10. 子進程.join():主進程等待寫入進程執行完成之後程序再往下繼續執行
11. 子進程.daemon = True:設置守護主進程, 主進程退出後子進程直接銷燬了。
12. 子進程.terminate():讓子進程直接銷燬
13. queue = multiprocessing.Queue(3):# 建立消息隊列,3表示消息隊列最大個數
13.1 queue.put(' '):向變量名裏面傳輸數據,隊列滿了在放入數據, 就不能放入數據了,直到消息異步
隊列有空閒位置才能再放入數據
13.2 queue.put_nowait:不會等待隊列有空閒位置再放入數據,若是數據放入不成功就直接崩async
潰。建議: 放入數據使用put,由於比較安全不會崩潰
13.3 queue.full():查看隊列是不是滿的。坑點: 只使用put放入數據直接判斷隊列是否爲空獲取的
結果不正確,由於沒有等隊列把數據寫完直接就取獲取了,那麼這是隊列是空的
13.4 queue.qsize():獲得隊列裏面數據的個數,mac 版本不能使用qsize()
13.5 queue.empty():判斷隊列是否爲空,空獲得True,有數據獲得Flase
13.6 queue.get():獲取隊列的數據,隊列爲空,使用get會等待,直到隊列有數據之後再取值
13.7 queue.get_nowait():隊列爲空,取值的時候不等待,可是取不到值那麼直接崩潰了。建
議:獲取隊列的數據統一get,由於能保證代碼不會有問題
14. multiprocessing.Pool(3):建立進程池 3: 進程池中進程的最大個數。注:進程池:,池子裏面放的都是進程,進程的建立有進程池負責,執行任務的時候循環利用指定進程大小個數執行對應的任務
14.1 apply():表示同步執行,表示一個任務執行完成另一個任務才能執行
14.2 apply_async():表示異步執行,異步是不會等待其它任務執行完成之後再去執行,多個任務一
起執行
14.3 pool.close():關閉進程池,再也不接收其它任務
14.4 pool.join():主進程等待進程池執行完成之後再退出
15 queue = multiprocessing.Manager().Queue():建立進程池的queue
協 程
協程:又稱爲微線程,也能夠說成用戶級線程, 在不開闢線程的基礎上能夠完成多任務
如何理解協程: 只要在def裏面只看到一個yield關鍵字表示就是協程
學習協程目的: 在單線程的基礎上能夠完成多任務,多個任務按照必定順序交替執行
迭代:使用for循環遍歷取值的過程就叫作迭代。可迭代對象有: 元組,列表,字典,字符串,集合,range;int對象不是可迭代對象
1.from collections import Iterable : 可迭代類型k,
2.isinstance((3, 5), Iterable):斷定(3,5)是否是可迭代類型。擴展:-之後能夠經過isinstance判斷函數的參數或者方法的參數是不是指定類型,(3, 5)斷定的對象,Iterable斷定的類型
2.自定義可迭代對象
2.1 在類裏面提供了__iter__方法建立的對象就是可迭代對象。
2.2 自定義迭代器對象: 在類裏面提供__iter__和__next__的方法建立的對象就是迭代器對象
2.3 迭代器的做用: 記錄當前數據的位置之後獲取下一個位置的值
2.4 總結: 可迭代對象的本質:經過迭代器依次獲取對象中的數據須要返回一個迭代器
2.5 使用for遍歷可迭代對象依次獲取對應的數據
2.6 擴展 raise StopIteration表示越界,拋出中止迭代的異常信息
3. iter函數:獲取可迭代對象的迭代器, 會調用可迭代對象身上的__iter__方法
4. next函數:獲取迭代器中下一個值,會調用迭代器對象身上的__next__方法
5.iter獲取可迭代對象.的迭代器,獲得的是<__main__.StudentIterator object at 0x00000000027A7828>
6.生成器: 是一個特殊的迭代器,也就是說生成器依然可使用next函數和for循環遍歷取值
6.1建立生成器方式1:my_generator = (i * 2 for i in range(10)) 建立生成器後for來遍歷獲得結果
6.2建立生成器2:使用yield,只要在def裏面看到yield表示生成器。代碼執行yield會暫停,把結果返
回給外界,再次啓動生成器會在暫停的位置繼續往下執行
6.3代碼執行到return關鍵字的時候會拋出中止迭代的異常,後面就是有數據也不會取了;生成器裏
面使用return關鍵字語法上沒有問題,可是注意代碼執行到return關鍵字會拋出中止迭代的異
常;python3執行return, python2不支持。
6.4 yield每次啓動生成器yield都會返回一個值,也就是說屢次啓動生成器能夠返回屢次值;return
只會返回一次值,而且拋出中止迭代異常,獲取返回值經過捕獲異常取到返回值
7.調用生成器的send方法
7.1能夠根據參數判斷是否能夠中止迭代,執行return關鍵字就能夠中止
7.2總結: send能夠給生成器傳參數,可是第一次啓動生成器只能傳None,通常第一次啓動生成器
使用next函數
8.greenlet: 爲了更好的讓程序員使用協程可使用greenlet,由於greent封裝的yield
8.1 變量名 = greenlet.greenlet(所執行的任務名):建立協程執行對應的任務
8.2 變量名.switch():切換到第一個協程執行對應的任務
9.from gevent import monkey
9.1 monkey.patch_all():須要打補丁,讓gevent可以識別系統的耗時操做及網絡延時操做
10. import gevent:gevent框架封裝Greenlet,會根據耗時操做自動完成協程之間的切換執行
10.1 pip3 install gevent :下載gevent
10.2 變量名 = gevent.spawn(所執行的任務名):建立協程完成對應的任務
10.3 變量名 .join():讓主線程等待協程執行完成之後程序再退出
11. import urllib.request : 導入網絡請求模塊
11.1 urllib.request.urlopen():根據圖片地址加載網絡資源數據
11.2 gevent.spawn(download_img, img_url1, "1.jpg"):建立協程對象指定對應的任務
11.2.1 函數名,
11.2.2 函數對應的參數1: img_url1
11.2.3 函數對應的參數2: 圖片名
進程、線程、協程對比 1. 先有進程,而後進程裏面能夠建立多個線程,線程裏面能夠有多個協程 2. 進程之間不共享全局變量,線程之間共享全局變量,可是要注意資源競爭的問題 3. 多進程開發比單進程多線程開發穩定性要強,可是多進程開發比多線程開發資源開銷要大 4. 線程之間執行時無序的,可是協程在不開闢線程的基礎上能夠完成多任務,多個任務按照必定順序交替執行 5. 協程之後主要用在網絡爬蟲,網絡請求,每開闢協程大概須要5k空間 6. 開闢一個線程大概須要512k空間,進程須要資源更多