1. 程式人生 > 程式設計 >python 使用事件物件asyncio.Event來同步協程的操作

python 使用事件物件asyncio.Event來同步協程的操作

事件物件asyncio.Event是基於threading.Event來實現的。

事件可以一個訊號觸發多個協程同步工作,

例子如下:

import asyncio
import functools
 
def set_event(event):
  print('setting event in callback')
  event.set()
 
async def coro1(event):
  print('coro1 waiting for event')
  await event.wait()
  print('coro1 triggered')
 
async def coro2(event):
  print('coro2 waiting for event')
  await event.wait()
  print('coro2 triggered')
 
async def main(loop):
  # Create a shared event
  event = asyncio.Event()
  print('event start state: {}'.format(event.is_set()))
 
  loop.call_later(
    0.1,functools.partial(set_event,event)
  )
 
  await asyncio.wait([coro1(event),coro2(event)])
  print('event end state: {}'.format(event.is_set()))
 
event_loop = asyncio.get_event_loop()
try:
  event_loop.run_until_complete(main(event_loop))
finally:
  event_loop.close()

輸出如下:

event start state: False
coro2 waiting for event
coro1 waiting for event
setting event in callback
coro2 triggered
coro1 triggered
event end state: True

補充知識: python裡使用協程來建立echo客戶端

在這個例子裡使用asyncio.Protocol來建立一個echo客戶端,先匯入庫asyncio和logging。

接著定義傳送的訊息MESSAGES。

建立連線伺服器的地址SERVER_ADDRESS,接著建立EchoClient類,它是繼承asyncio.Protocol。

在這個類的建構函式裡,接收兩個引數messages和future,

messages是指定要傳送的訊息資料,future是用來通知socket接收資料完成或者伺服器關閉socket的事件通知,以便事件迴圈知道這個協程已經完成了,就可以退出整個程式。

connection_made函式是當socket連線到伺服器時呼叫,它就立即傳送資料給伺服器,資料傳送完成之後傳送了eof標記。

伺服器收到資料和標誌都回復客戶端,客戶端data_received函式接收資料,eof_received函式接收結束標記。

connection_lost函式收到伺服器斷開連線。

這行程式碼:

client_completed = asyncio.Future()

建立一個協程完成的觸發事件。

由於event_loop.create_connection函式只能接收一個引數,需要使用functools.partial來進行多個引數包裝成一個引數。

後面通過事件迴圈來執行協程。

import asyncio
import functools
import logging
import sys
 
MESSAGES = [
  b'This is the message. ',b'It will be sent ',b'in parts.',]
SERVER_ADDRESS = ('localhost',10000)
 
class EchoClient(asyncio.Protocol):
 
  def __init__(self,messages,future):
    super().__init__()
    self.messages = messages
    self.log = logging.getLogger('EchoClient')
    self.f = future
 
  def connection_made(self,transport):
    self.transport = transport
    self.address = transport.get_extra_info('peername')
    self.log.debug(
      'connecting to {} port {}'.format(*self.address)
    )
    # This could be transport.writelines() except that
    # would make it harder to show each part of the message
    # being sent.
    for msg in self.messages:
      transport.write(msg)
      self.log.debug('sending {!r}'.format(msg))
    if transport.can_write_eof():
      transport.write_eof()
 
  def data_received(self,data):
    self.log.debug('received {!r}'.format(data))
 
  def eof_received(self):
    self.log.debug('received EOF')
    self.transport.close()
    if not self.f.done():
      self.f.set_result(True)
 
  def connection_lost(self,exc):
    self.log.debug('server closed connection')
    self.transport.close()
    if not self.f.done():
      self.f.set_result(True)
    super().connection_lost(exc)
 
logging.basicConfig(
  level=logging.DEBUG,format='%(name)s: %(message)s',stream=sys.stderr,)
log = logging.getLogger('main')
 
event_loop = asyncio.get_event_loop()
 
client_completed = asyncio.Future()
 
client_factory = functools.partial(
  EchoClient,messages=MESSAGES,future=client_completed,)
factory_coroutine = event_loop.create_connection(
  client_factory,*SERVER_ADDRESS,)
 
log.debug('waiting for client to complete')
try:
  event_loop.run_until_complete(factory_coroutine)
  event_loop.run_until_complete(client_completed)
finally:
  log.debug('closing event loop')
  event_loop.close()

以上這篇python 使用事件物件asyncio.Event來同步協程的操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。