Python Language
Asyncio मॉड्यूल
खोज…
Coroutine और प्रत्यायोजन सिंटेक्स
पायथन 3.5+ जारी होने से पहले, asyncio
मॉड्यूल ने एसिंक्रोनस कॉल की नकल करने के लिए जनरेटर का उपयोग किया था और इस प्रकार वर्तमान पायथन 3.5 रिलीज की तुलना में एक अलग वाक्यविन्यास था।
पायथन 3.5 ने async
और await
खोजशब्दों को पेश किया। ध्यान दें कि await func()
कॉल के आसपास कोष्ठक की कमी है।
import asyncio
async def main():
print(await func())
async def func():
# Do time intensive stuff...
return "Hello, world!"
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
पायथन 3.5 से पहले, @asyncio.coroutine
डेकोरेटर का उपयोग एक @asyncio.coroutine
को परिभाषित करने के लिए किया गया था। अभिव्यक्ति से उपज जनरेटर प्रतिनिधिमंडल के लिए इस्तेमाल किया गया था। yield from func()
चारों ओर कोष्ठक पर ध्यान दें yield from func()
।
import asyncio
@asyncio.coroutine
def main():
print((yield from func()))
@asyncio.coroutine
def func():
# Do time intensive stuff..
return "Hello, world!"
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
यहां एक उदाहरण दिया गया है, जिसमें दिखाया गया है कि कैसे दो कार्यों को अतुल्यकालिक रूप से चलाया जा सकता है:
import asyncio
async def cor1():
print("cor1 start")
for i in range(10):
await asyncio.sleep(1.5)
print("cor1", i)
async def cor2():
print("cor2 start")
for i in range(15):
await asyncio.sleep(1)
print("cor2", i)
loop = asyncio.get_event_loop()
cors = asyncio.wait([cor1(), cor2()])
loop.run_until_complete(cors)
अतुल्यकालिक निष्पादनकर्ता
नोट: पायथन 3.5+ async / वेट सिंटैक्स का उपयोग करता है
asyncio
का समर्थन करता है के उपयोग के Executor
में पाया वस्तुओं concurrent.futures
शेड्यूलिंग कार्यों एसिंक्रोनस रूप के लिए। घटना छोरों कार्य हो run_in_executor()
जो एक लेता है Executor
वस्तु, एक Callable
, और प्रतिदेय के मानकों।
एक Executor
लिए एक कार्य का समय निर्धारण
import asyncio
from concurrent.futures import ThreadPoolExecutor
def func(a, b):
# Do time intensive stuff...
return a + b
async def main(loop):
executor = ThreadPoolExecutor()
result = await loop.run_in_executor(executor, func, "Hello,", " world!")
print(result)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
प्रत्येक ईवेंट लूप में एक "डिफ़ॉल्ट" Executor
स्लॉट भी होता है जिसे Executor
को सौंपा जा सकता है। एक निर्दिष्ट करने के लिए Executor
पाश आप उपयोग से और अनुसूची कार्यों set_default_executor()
विधि।
import asyncio
from concurrent.futures import ThreadPoolExecutor
def func(a, b):
# Do time intensive stuff...
return a + b
async def main(loop):
# NOTE: Using `None` as the first parameter designates the `default` Executor.
result = await loop.run_in_executor(None, func, "Hello,", " world!")
print(result)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.set_default_executor(ThreadPoolExecutor())
loop.run_until_complete(main(loop))
वहाँ के दो मुख्य प्रकार हैं Executor
में concurrent.futures
, ThreadPoolExecutor
और ProcessPoolExecutor
। ThreadPoolExecutor
में थ्रेड्स का एक पूल होता है जिसे या तो मैन्युफैक्चरर द्वारा थ्रेड की एक विशिष्ट संख्या में सेट किया जा सकता है या मशीन समय पर कोर की संख्या के लिए डिफॉल्ट हो सकता है। ThreadPoolExecutor
थ्रेड्स के पूल का उपयोग करता है ताकि इसे सौंपे गए कार्यों को निष्पादित किया जा सके और आमतौर पर I / O बाउंड ऑपरेशंस के बजाय सीपीयू-बाउंड ऑपरेशंस में बेहतर है। इसके विपरीत ProcessPoolExecutor
जो इसे सौंपे गए प्रत्येक कार्य के लिए एक नई प्रक्रिया ProcessPoolExecutor
है। ProcessPoolExecutor
केवल कार्यों और पैरामीटर picklable हैं ले जा सकते हैं। सबसे आम गैर-पिकलेबल कार्य वस्तुओं के तरीके हैं। यदि आप किसी ऑब्जेक्ट की विधि को किसी कार्य में Executor
रूप में शेड्यूल करते हैं, तो आपको एक ThreadPoolExecutor
उपयोग करना होगा।
UVLoop का उपयोग करना
uvloop
लिए एक कार्यान्वयन है, जो asyncio.AbstractEventLoop
पर आधारित है (नोडज द्वारा प्रयुक्त)। यह 99% asyncio
सुविधाओं के asyncio
है और पारंपरिक asyncio.EventLoop
तुलना में बहुत तेज है। uvloop
वर्तमान में विंडोज पर उपलब्ध नहीं है, इसे pip install uvloop
साथ pip install uvloop
।
import asyncio
import uvloop
if __name__ == "__main__":
asyncio.set_event_loop(uvloop.new_event_loop())
# Do your stuff here ...
एक भी सेट करके घटना पाश कारखाने को बदल सकते हैं EventLoopPolicy
में से एक के लिए uvloop
।
import asyncio
import uvloop
if __name__ == "__main__":
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.new_event_loop()
तुल्यकालन आदिम: घटना
संकल्पना
एक से अधिक coroutines के शेड्यूल को सिंक्रनाइज़ करने के लिए किसी Event
का उपयोग करें।
सीधे शब्दों में कहें, एक घटना दौड़ की दौड़ में बंदूक की गोली की तरह है: यह धावकों को शुरुआती ब्लॉकों से दूर जाने देता है।
उदाहरण
import asyncio
# event trigger function
def trigger(event):
print('EVENT SET')
event.set() # wake up coroutines waiting
# event consumers
async def consumer_a(event):
consumer_name = 'Consumer A'
print('{} waiting'.format(consumer_name))
await event.wait()
print('{} triggered'.format(consumer_name))
async def consumer_b(event):
consumer_name = 'Consumer B'
print('{} waiting'.format(consumer_name))
await event.wait()
print('{} triggered'.format(consumer_name))
# event
event = asyncio.Event()
# wrap coroutines in one future
main_future = asyncio.wait([consumer_a(event),
consumer_b(event)])
# event loop
event_loop = asyncio.get_event_loop()
event_loop.call_later(0.1, functools.partial(trigger, event)) # trigger event in 0.1 sec
# complete main_future
done, pending = event_loop.run_until_complete(main_future)
आउटपुट:
उपभोक्ता बी इंतजार कर रहा है
उपभोक्ता एक प्रतीक्षा
घटना सेट
उपभोक्ता बी ने ट्रिगर किया
उपभोक्ता ए ने ट्रिगर किया
एक साधारण वेबसैट
यहां हम एसिंको का उपयोग करके एक सरल इको वेबस्कैट asyncio
। हम एक सर्वर से कनेक्ट करने और संदेश भेजने / प्राप्त करने के लिए कोरआउट्स को परिभाषित करते हैं। वेबस्कैट के संवाद main
कोरआउट में चलते हैं, जो एक इवेंट लूप द्वारा चलाया जाता है। यह उदाहरण एक पूर्व पोस्ट से संशोधित है।
import asyncio
import aiohttp
session = aiohttp.ClientSession() # handles the context manager
class EchoWebsocket:
async def connect(self):
self.websocket = await session.ws_connect("wss://echo.websocket.org")
async def send(self, message):
self.websocket.send_str(message)
async def receive(self):
result = (await self.websocket.receive())
return result.data
async def main():
echo = EchoWebsocket()
await echo.connect()
await echo.send("Hello World!")
print(await echo.receive()) # "Hello World!"
if __name__ == '__main__':
# The main loop
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Asyncio के बारे में आम धारणा
शायद asnycio
बारे में सबसे आम गलतफहमी यह है कि यह आपको समानांतर में किसी भी कार्य को चलाने देता है - GIL (वैश्विक दुभाषिया लॉक) को asnycio
और इसलिए समानांतर (अलग थ्रेड पर) में अवरुद्ध नौकरियों को निष्पादित करता है। यह नहीं है !
asyncio
(और पुस्तकालयों कि asyncio
के साथ सहयोग करने के लिए बनाया गया है) coroutines पर निर्माण: कार्य है कि (सहयोगी) नियंत्रण प्रवाह वापस बुला समारोह में उपज। उपरोक्त उदाहरणों में asyncio.sleep
ध्यान दें। यह एक गैर-अवरोधक कोरटाइन का एक उदाहरण है जो 'पृष्ठभूमि में' प्रतीक्षा करता है और कॉलिंग फ़ंक्शन (जब await
साथ कहा जाता है) पर नियंत्रण प्रवाह देता है। time.sleep
एक अवरुद्ध फ़ंक्शन का एक उदाहरण है। कार्यक्रम का निष्पादन प्रवाह बस वहीं रुक जाएगा और केवल समय के बाद वापस आ जाएगा। time.sleep
समाप्त हो गया है।
एक वास्तविक-जीवंत उदाहरण requests
पुस्तकालय है जिसमें केवल अवरुद्ध कार्यों पर (समय के लिए) समाहित है। यदि आप asyncio
भीतर इसके किसी भी कार्य को कहते हैं, तो कोई संगामिति नहीं है। aiohttp
दूसरी तरफ से बनाया गया था asyncio
दिमाग में। इसके कोरआउट समवर्ती रूप से चलेंगे।
यदि आपके पास लंबे समय से सीपीयू-बाउंड कार्य हैं, तो आप समानांतर
asyncio
में चलाना चाहते हैं जो आपके लिए नहीं है। इसके लिए आपकोthreads
याmultiprocessing
आवश्यकता है।यदि आपके पास IO- बाउंड जॉब्स हैं, तो आप उन्हें
asyncio
का उपयोग करके समवर्ती रूप से चला सकते हैं।