溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python中Event事件、進程池、線程池以及協(xié)程的實例介紹

發(fā)布時間:2021-09-04 16:47:24 來源:億速云 閱讀:238 作者:chen 欄目:開發(fā)技術(shù)

這篇文章主要介紹“python中Event事件、進程池、線程池以及協(xié)程的實例介紹”,在日常操作中,相信很多人在python中Event事件、進程池、線程池以及協(xié)程的實例介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”python中Event事件、進程池、線程池以及協(xié)程的實例介紹”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

Event事件

用來控制線程的執(zhí)行

出現(xiàn)e.wait(),就會把這個線程設(shè)置為False,就不能執(zhí)行這個任務(wù);

只要有一個線程出現(xiàn)e.set(),就會告訴Event對象,把有e.wait的用戶全部改為True,剩余的任務(wù)就會立馬去執(zhí)行。由一些線程去控制另一些線程,中間通過Event。

from threading import Event
from threading import Thread
import time
# 調(diào)用Event實例化出對象
e = Event()
#
# # 若該方法出現(xiàn)在任務(wù)中,則為False,阻塞
# e.wait() # False
# # 若該方法出現(xiàn)在任務(wù)中,則將其他線程的False改為True,進入就緒態(tài)和運行態(tài)
# e.set() # True
def light():
 print('紅燈亮...')
 time.sleep(5)
 # 應(yīng)該發(fā)出信號,告訴其他線程準備執(zhí)行
 e.set() # 將car中的False變?yōu)門rue
 print('綠燈亮...')
def car(name):
 print('正在等紅燈...')
 # 讓所有汽車任務(wù)進入阻塞態(tài)
 e.wait() # False
 print(f'{name}正在加速飄逸...')
# 讓一個light線程控制多個car線程
t = Thread(target=light)
t.start()

for i in range(10):
 t = Thread(target=car, args=(f'汽車{i}號', ))
 t.start()

進程池與線程池

進程池與線程池是用來控制當前程序允許創(chuàng)建(進程/線程)的數(shù)量

作用:保證在硬件允許的范圍內(nèi)創(chuàng)建(進程/線程)的數(shù)量

線程池使用一:

from concurrent.futures import ThreadPoolExecutor
import time
pool = ThreadPoolExecutor(5) # 5代表只能開啟5個進程, 不加默認使用cpu的進程數(shù)
# ThreadPoolExecutor(5) # 5代表只能開啟5個線程
# pool.submit() #異步提交任務(wù), 括號里傳函數(shù)地址
def task():
 print('線程任務(wù)開始了...')
 time.sleep(1)
 print('線程任務(wù)結(jié)束了...')
for line in range(5):
 pool.submit(task)

使用二:

from concurrent.futures import ThreadPoolExecutor
import time

pool = ThreadPoolExecutor(5) # 5代表只能開啟5個進程, 不加默認使用cpu的進程數(shù)

# ThreadPoolExecutor(5) # 5代表只能開啟5個線程
# pool.submit() #異步提交任務(wù), 括號里傳函數(shù)地址
def task():
 print('線程任務(wù)開始了...')
 time.sleep(1)
 print('線程任務(wù)結(jié)束了...')
 return 123
# 回調(diào)函數(shù)
def call_back(res):
 print(type(res))
 res2 = res.result() # 注意:賦值操作不要與接收的res同名
 print(res2)
for line in range(5):
 pool.submit(task).add_done_callback(call_back)

pool.shutdown() 會讓所有線程池的任務(wù)結(jié)束后,才往下執(zhí)行代碼

多線程爬取梨視頻

利用requests模塊,封裝底層socket套接字

  • 主頁中獲取所有視頻id號,拼接視頻詳情頁url

  • 在視頻詳情頁中獲取真實視頻url srcUrl=

  • 往真實視頻url地址發(fā)送請求獲取 視頻 二進制數(shù)據(jù)

  • 最后把視頻二進制數(shù)據(jù)保存到本地

協(xié)程

  • 進程: 資源單位

  • 線程: 執(zhí)行單位

  • 協(xié)程: 在單線程下實現(xiàn)并發(fā)

注意: 協(xié)程不是操作系統(tǒng)資源,目的是讓單線程實現(xiàn)并發(fā)

協(xié)程目的

  • 操作系統(tǒng):使用多道技術(shù),切換 + 保存狀態(tài),一個是遇到IO, 另一個是CPU執(zhí)行時間過長

  • 協(xié)程:通過手動模擬操作系統(tǒng) “多道計數(shù)”, 實現(xiàn) 切換 + 保存狀態(tài)

    • 手動實現(xiàn),遇到IO切換,欺騙操作系統(tǒng)誤以為沒有IO操作

    • 單線程時,遇到IO,就切換 + 保存狀態(tài)

    • 單線程時,對于計算密集型,來回切換 + 保存狀態(tài)反而效率更低

優(yōu)點:在IO密集型的情況下,會提高效率

缺點:若在計算密集型的情況下,來回切換,反而效率更低

import time

def func1():
 for i in range(10000000):
  i+1

def func2():
 for i in range(10000000):
  i+1
start = time.time()
func1()
func2()
stop = time.time()
print(stop - start) # 1.0312113761901855


# 基于yield實現(xiàn)并發(fā) 在計算密集型的情況下效率更低

def func1():
 while True:
  10000000+1
  yield

def func2():
 g = func1()
 for i in range(10000000):
  i+1
  next(g) # 每次執(zhí)行next相當于切換到func1下面
start = time.time()
func2()
stop = time.time()
print(stop - start) # 1.3294126987457275

gevent

gevent是一個第三方模塊,可以幫你監(jiān)聽IO操作,并切換

使用gevent的目的:在單線程下實現(xiàn),遇到IO就會 保存狀態(tài) + 切換

import time
from gevent import monkey

monkey.patch_all() # 可以監(jiān)聽該程序下所有的IO操作
from gevent import spawn, joinall # 用于做切換 + 保存狀態(tài)
def func1():
 print('1')
 time.sleep(1) # IO操作
def func2():
 print('2')
 time.sleep(3)
def func3():
 print('3')
 time.sleep(5)
start = time.time()
s1 = spawn(func1)
s2 = spawn(func2)
s3 = spawn(func3)

s1.join() # 發(fā)送信號,相當于等待自己(在單線程的情況下)
s2.join()
s3.join()

# joinall((s1, s2, s3)) # 一個個執(zhí)行很麻煩,可以用joinall把這些全部裝進去

end = time.time()
print(end - start) # 5.006161451339722

TCP服務(wù)端socket套接字實現(xiàn)協(xié)程

服務(wù)端:

from gevent import monkey
from gevent import spawn
import socket

monkey.patch_all()
server = socket.socket()
server.bind(('127.0.0.1', 9999))
server.listen(5)

def task(conn):
 while True:
  try:
   data = conn.recv(1024)
   if len(data) == 0:
    break
   print(data.decode('utf-8'))
   send_data = data.upper()
   conn.send(send_data)

  except Exception:
   break
 conn.close()
def server2():
 while True:
  conn, addr = server.accept()
  print(addr)
  spawn(task, conn)
if __name__ == '__main__':
 s = spawn(server2)
 s.join()

客戶端:

import socket
from threading import Thread, current_thread

def client():
 client = socket.socket()
 client.connect(('127.0.0.1', 9999))

 number = 0
 while True:
  send_data = f'{current_thread().name} {number}'
  client.send(send_data.encode('utf-8'))

  data = client.recv(1024)
  print(data.decode('utf-8'))
  number += 1


for i in range(400):
 t = Thread(target=client)
 t.start()

到此,關(guān)于“python中Event事件、進程池、線程池以及協(xié)程的實例介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI