1. 程式人生 > >python協程,執行緒的其他方法

python協程,執行緒的其他方法

OK 這一篇主要是協程的,還落下了點執行緒的方法,先說執行緒,

  1. 執行緒池
  2. 執行緒池回撥函式
  3. 協程

 

一. 執行緒池  

   執行緒池顧名思義就是跟是跟程序池一樣的

  到這裡就差我們的執行緒池沒有講了,我們用一個新的模組給大家講,早期的時候我們沒有執行緒池,現在python提供了一個新的標準或者說內建的模組,這個模組裡面提供了新的執行緒池和程序池,之前我們說的程序池是在multiprocessing裡面的,現在這個在這個新的模組裡面,他倆用法上是一樣的。

 

為什麼要將程序池和執行緒池放到一起呢,是為了統一使用方式,使用threadPollExecutor和ProcessPollExecutor的方式一樣,而且只要通過這個concurrent.futures匯入就可以直接用他們兩個了  

import    time
from   threading   import   current_thread        #這裡還是要匯入執行緒的current_thread方法,因為要用。
from   concurrent.futures   import    ThreadPoolExecutor,ProcessPoolExecutor    #這裡直接就把程序,執行緒一起匯入了,省事!呵呵呵。。。

def   f1(n,s):
  time.sleep(1)
  # print('%s號子執行緒'%current_thread().ident)
  print(n,s)
  return

if __name__ == '__main__':

  tp = ThreadPoolExecutor(4)    #執行緒池的方法(4)個執行緒
  # tp = ProcessPoolExecutor(4)
  # tp.map(f1,range(10))        #非同步提交任務,引數同樣是任務名稱,可迭代物件
  res_list = []
  for i in range(10):
    res = tp.submit(f1,i,'baobao')      #submit是給執行緒池非同步提交任務,
    #print(res)
    res.result()                       #取值這一步相當於把執行緒變成了一個同步的狀態,這一步
    res_list.append(res)        #是為了取到f1中return的值,才這樣取值的,要不就直接加個

                    #tp.shutdown() 直接就四個四個列印了。所以才加的列表。 
  

  tp.shutdown()            #主執行緒等待所有提交給執行緒池的任務,全部執行完畢 close + join
  for r in res_list:             #加到列表裡是為了能四個四個取值,把所有的返回值地址放到一個列表
    print(r.result())        #再迴圈取值,這樣就能四個四個拿值了,要不這樣的話,就成了同步取值
  print('主執行緒結束')        #了就沒效率了

 

二.執行緒的回撥函式

跟程序一樣,單詞不一樣。

import    time
from   threading   import   current_thread
from    concurrent.futures    import    ThreadPoolExecutor,ProcessPoolExecutor

def   f1(n,s):
  return n+s

def   f2(n):

  print('回撥函式>>>',n.result())
if __name__ == '__main__':

  tp = ThreadPoolExecutor(4)

  res = tp.submit(f1,11,12).add_done_callback(f2)       #把f1的值,返回給f2  記住方法add_done_callback(f2)

  # print(res.result())

 

三.協程

  進入主題--協程

  協程  這個詞在官方中是沒有定義這樣的一個方法的,這個說句大白話,協程 這個方法是

  大佬程式設計師,自己YY出來的。

本節的主題是基於單執行緒來實現併發,即只用一個主執行緒(很明顯可利用的cpu只有一個)情況下實現併發,為此我們需要先回顧下併發的本質:切換+儲存狀態

  cpu正在執行一個任務,會在兩種情況下切走去執行其他的任務(切換由作業系統強制控制),一種情況是該任務發生了阻塞,另外一種情況是該任務計算的時間過長或有一個優先順序更高的程式替代了它

  協程本質上就是一個執行緒,以前執行緒任務的切換是由作業系統控制的,遇到I/O自動切換,現在我們用協程的目的就是較少作業系統切換的開銷(開關執行緒,建立暫存器、堆疊等,在他們之間進行切換等),在我們自己的程式裡面來控制任務的切換。

#1 yiled可以儲存狀態,yield的狀態儲存與作業系統的儲存執行緒狀態很像,但是yield是程式碼級別控制的,更輕量級
#2 send可以把一個函式的結果傳給另外一個函式,以此實現單執行緒內程式之間的切換 
上程式碼

import   gevent
from   gevent   import   monkey;monkey.patch_all()          #匯入gevent模組中的monkey;monkey.patch_all()  
import    time                    #是為了遇到io阻塞直接進行下一任務的方法
import    threading

def   f1():
  print('第一次f1')
  # print(threading.current_thread().getName())  #這一步是為了證明兩協程是一個執行緒

                       #這一步是看名字,兩名字都一樣,都是同一個執行緒名字   
  # gevent.sleep(1)    #這一步是相當於time.sleep的功能的一個io阻塞,
  time.sleep(2)
  print('第二次f1')

def   f2():
  # print(threading.current_thread().getName())
  print('第一次f2')
  # gevent.sleep(2)
  time.sleep(2)
  print('第二次f2')

s = time.time()
g1 = gevent.spawn(f1)         #非同步提交了f1任務   是非同步,記住是非同步 
g2 = gevent.spawn(f2)         #非同步提交了f2任務
# g1.join()
# g2.join()
gevent.joinall([g1,g2])        #這是一個小技巧,統一把倆都加上了join,不重要
e = time.time()
print('執行時間:',e-s)
print('主程式任務')

 

#這就是協程了

二:第一種情況的切換。在任務一遇到io情況下,切到任務二去執行,這樣就可以利用任務一阻塞的時間完成任務二的計算,效率的提升就在於此。

協程的本質就是在單執行緒下,由使用者自己控制一個任務遇到io阻塞了就切換另外一個任務去執行,以此來提升效率。為了實現它,我們需要找尋一種可以同時滿足以下條件的解決方案

#1. 可以控制多個任務之間的切換,切換之前將任務的狀態儲存下來,以便重新執行時,可以基於暫停的位置繼續執行。

#2. 作為1的補充:可以檢測io操作,在遇到io操作的情況下才發生切換
一個程序裡面可以開200個執行緒,一個執行緒裡面可以開500個協程,,,
OK到此,程序,執行緒,協程都結束了,統稱併發程式設計,下一篇就資料庫了,好好學呀大家,
好好學習!天天向上!