از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
آموزش Python async/wait
سرفصلهای مطلب
برنامه نویسی ناهمزمان در چند سال گذشته طرفداران زیادی پیدا کرده است و دلیل خوبی هم دارد. اگرچه می تواند دشوارتر از سبک خطی سنتی باشد، اما بسیار کارآمدتر است.
برای مثال، بهجای اینکه منتظر بمانید تا درخواست HTTP قبل از ادامه اجرا تمام شود، با برنامههای همگام Python میتوانید درخواست را ارسال کنید و در حالی که منتظر اتمام درخواست HTTP هستید، کارهای دیگری را انجام دهید که در یک صف منتظر هستند. شاید برای درست کردن منطق کمی بیشتر فکر کنید، اما با منابع کمتر میتوانید کارهای بسیار بیشتری را انجام دهید.
حتی در آن زمان، نحو و اجرای توابع ناهمزمان در زبانهایی مانند پایتون در واقع چندان سخت نیست. اکنون، جاوا اسکریپت داستان متفاوتی است، اما به نظر می رسد پایتون آن را به خوبی اجرا می کند.
به نظر می رسد ناهمزمانی بودن دلیل بزرگی است که Node.js برای برنامه نویسی سمت سرور بسیار محبوب است. بسیاری از کدهایی که می نویسیم، به خصوص در برنامه های سنگین IO مانند وب سایت ها، بستگی دارد روی منابع خارجی این می تواند هر چیزی باشد، از تماس پایگاه داده از راه دور گرفته تا POSTing و سرویس REST. به محض درخواست هر یک از این منابع، کد شما بدون هیچ کاری منتظر است.
با برنامهنویسی ناهمزمان، به کد خود اجازه میدهید تا کارهای دیگر را انجام دهد در حالی که منتظر پاسخ این منابع دیگر هستید.
کوروتین ها
یک تابع ناهمزمان در پایتون معمولاً “coroutine” نامیده می شود، که فقط تابعی است که از async
کلمه کلیدی یا کلمه ای که با آن تزئین شده است @asyncio.coroutine
. هر یک از توابع زیر به عنوان یک برنامه کار می کنند و به طور موثر از نظر نوع معادل هستند:
import asyncio
async def ping_server(ip):
pass
@asyncio.coroutine
def load_file(path):
pass
اینها توابع ویژه ای هستند که هنگام فراخوانی اشیاء کوروتین را برمی گرداند. اگر با Promise جاوا اسکریپت آشنایی دارید، می توانید این شیء برگشتی را تقریباً مانند یک Promise در نظر بگیرید. فراخوانی هر یک از اینها در واقع آنها را اجرا نمی کند، اما در عوض a روتین شی برگردانده می شود، که سپس می تواند به حلقه رویداد ارسال شود تا بعدا اجرا شود روی.
در صورتی که نیاز دارید تعیین کنید که آیا یک تابع یک برنامه است یا نه، asyncio
روش را ارائه می دهد asyncio.iscoroutinefunction(func)
که دقیقا این کار را برای شما انجام می دهد. یا، اگر شما نیاز به تعیین اینکه آیا یک شیء برگشتی از یک تابع یک شی کوروتین است، می توانید استفاده کنید asyncio.iscoroutine(obj)
بجای.
بازده از
چند راه برای فراخوانی یک کوروتین وجود دارد که یکی از آنها این است yield from
روش. این در پایتون 3.3 معرفی شد و در پایتون 3.5 به شکل async/await
(که در ادامه به آن خواهیم پرداخت).
این yield from
عبارت را می توان به صورت زیر استفاده کرد:
import asyncio
@asyncio.coroutine
def get_json(client, url):
file_content = yield from load_file('/Users/scott/data.txt')
همانطور که می بینید، yield from
در یک تابع تزئین شده با استفاده می شود @asyncio.coroutine
. اگر می خواهید امتحان کنید و استفاده کنید yield from
در خارج از این تابع، خطای زیر را از پایتون دریافت خواهید کرد:
File "main.py", line 1
file_content = yield from load_file('/Users/scott/data.txt')
^
SyntaxError: 'yield' outside function
برای استفاده از این نحو، باید در تابع دیگری باشد (معمولاً با تزئین کننده کوروتین).
همگام سازی/انتظار
نحو جدیدتر و تمیزتر استفاده از آن است async/await
کلید واژه ها. معرفی شده در پایتون 3.5، async
برای اعلان یک تابع به عنوان یک کوروتین استفاده می شود، بسیار شبیه به آنچه که @asyncio.coroutine
دکوراتور انجام می دهد. با قرار دادن آن در جلوی تعریف می توان آن را به تابع اعمال کرد:
async def ping_server(ip):
برای فراخوانی واقعی این تابع، از آن استفاده می کنیم await
، بجای yield from
، اما تقریباً به همین ترتیب:
async def ping_local():
return await ping_server('192.168.1.1')
باز هم درست مثل yield from
، شما نمی توانید از این خارج از برنامه اصلی دیگر استفاده کنید، در غیر این صورت با یک خطای نحوی مواجه خواهید شد.
در پایتون 3.5، هر دو روش فراخوانی کوروتین ها پشتیبانی می شود، اما async/await
way به معنای نحو اولیه است.
اجرای حلقه رویداد
هیچ یک از موارد معمولی که در بالا توضیح دادم مهم (یا کارآمد) نخواهد بود اگر ندانید چگونه یک برنامه را شروع و اجرا کنید. حلقه رویداد. حلقه رویداد نقطه مرکزی اجرا برای توابع ناهمزمان است، بنابراین زمانی که میخواهید در واقع کوروتین را اجرا کنید، این همان چیزی است که استفاده میکنید.
حلقه رویداد چندین ویژگی را در اختیار شما قرار می دهد:
- ثبت، اجرا و لغو تماس های تاخیری (عملکردهای ناهمزمان)
- انتقال مشتری و سرور برای ارتباط ایجاد کنید
- ایجاد زیرفرآیند و انتقال برای ارتباط با برنامه دیگر
- فراخوانی تابع را به مجموعه ای از رشته ها واگذار کنید
در حالی که در واقع چند نوع پیکربندی و حلقه رویداد وجود دارد که می توانید از آنها استفاده کنید، اکثر برنامه هایی که می نویسید فقط باید از چیزی شبیه به این استفاده کنند تا یک تابع را برنامه ریزی کنند:
import asyncio
async def speak_async():
print('OMG asynchronicity!')
loop = asyncio.get_event_loop()
loop.run_until_complete(speak_async())
loop.close()
سه خط آخر چیزی است که ما در اینجا به آن علاقه داریم. با گرفتن حلقه رویداد پیش فرض (asyncio.get_event_loop()
)، برنامه ریزی و اجرای کار async، و سپس بستن حلقه زمانی که حلقه در حال اجرا است.
این loop.run_until_complete()
تابع در واقع مسدود میشود، بنابراین تا زمانی که همه روشهای ناهمزمان انجام نشوند، برنمیگردد. از آنجایی که ما فقط این را اجرا می کنیم روی در حالی که حلقه در حال انجام است، راهی وجود ندارد که بتواند به سمت جلو حرکت کند.
اکنون، ممکن است فکر کنید این خیلی مفید نیست زیرا ما در نهایت مسدود میشویم روی به هر حال حلقه رویداد (به جای فقط تماس های IO)، اما تصور کنید که کل برنامه خود را در یک تابع ناهمگام بپیچید، که سپس به شما امکان می دهد چندین درخواست ناهمزمان را همزمان اجرا کنید، مانند روی یک وب سرور
حتی میتوانید حلقه رویداد را به رشته خودش قطع کنید و به آن اجازه دهید تمام درخواستهای طولانی IO را رسیدگی کند در حالی که رشته اصلی منطق برنامه یا UI را مدیریت میکند.
یک مثال
خوب، پس بیایید یک مثال کمی بزرگتر ببینیم که واقعاً می توانیم اجرا کنیم. کد زیر یک برنامه ناهمزمان بسیار ساده است که JSON را از Reddit واکشی می کند، JSON را تجزیه می کند و پست های برتر روز را از /r/ چاپ می کند.python، /r/برنامه نویسی و /r/compsci.
روش اول نشان داده شده، get_json()
، توسط نامیده می شود get_reddit_top()
و فقط یک درخواست HTTP GET به URL مناسب Reddit ایجاد می کند. وقتی این با نامیده می شود await
، حلقه رویداد می تواند ادامه یابد روی و در حالی که منتظر دریافت پاسخ HTTP هستید، سایر برنامه های روتین را سرویس کنید. پس از انجام این کار، JSON به آن بازگردانده می شود get_reddit_top()
، تجزیه می شود و چاپ می شود.
import signal
import sys
import asyncio
import aiohttp
import json
loop = asyncio.get_event_loop()
client = aiohttp.ClientSession(loop=loop)
async def get_json(client, url):
async with client.get(url) as response:
assert response.status == 200
return await response.read()
async def get_reddit_top(subreddit, client):
data1 = await get_json(client, 'https://www.reddit.com/r/' + subreddit + '/top.json؟sort=top&t=day&limit=5')
j = json.loads(data1.decode('utf-8'))
for i in j('data')('children'):
score = i('data')('score')
title = i('data')('title')
link = i('data')('url')
print(str(score) + ': ' + title + ' (' + link + ')')
print('DONE:', subreddit + '\n')
def signal_handler(signal, frame):
loop.stop()
client.close()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
asyncio.ensure_future(get_reddit_top('python', client))
asyncio.ensure_future(get_reddit_top('programming', client))
asyncio.ensure_future(get_reddit_top('compsci', client))
loop.run_forever()
این کمی با کد نمونه ای که قبلا نشان دادیم متفاوت است. به منظور اجرای چند برنامه روی از حلقه رویداد استفاده می کنیم asyncio.ensure_future()
و سپس حلقه را برای همیشه اجرا کنید تا process همه چیز.
برای اجرای این، باید نصب کنید aiohttp
اول، که می توانید با PIP انجام دهید:
$ pip install aiohttp
اکنون فقط مطمئن شوید که آن را با پایتون 3.5 یا بالاتر اجرا می کنید، و باید خروجی مانند زیر دریافت کنید:
$ python main.py
46: Python async/await Tutorial (http://rasanegar.com/python-async-await-tutorial/)
16: Using game theory (and Python) to explain the dilemma of exchanging gifts. Turns out: giving a gift probably feels better than receiving one... (http://vknight.org/unpeudemath/code/2015/12/15/The-Prisoners-Dilemma-of-Christmas-Gifts/)
56: Which version of Python do you use? (This is a poll to compare the popularity of Python 2 vs. Python 3) (http://strawpoll.me/6299023)
DONE: python
71: The Semantics of Version Control - Wouter Swierstra (http://www.staff.science.uu.nl/~swier004/Talks/vc-semantics-15.pdf)
25: Favorite non-textbook CS books (https://www.reddit.com/r/compsci/comments/3xag9e/favorite_nontextbook_cs_books/)
13: CompSci Weekend SuperThread (December 18, 2015) (https://www.reddit.com/r/compsci/comments/3xacch/compsci_weekend_superthread_december_18_2015/)
DONE: compsci
1752: 684.8 TB of data is up for grabs due to publicly exposed MongoDB databases (https://blog.shodan.io/its-still-the-data-stupid/)
773: Instagram's Million Dollar Bug? (http://exfiltrated.com/research-Instagram-RCE.php)
387: Amazingly simple explanation of Diffie-Hellman. His channel has tons of amazing videos and only a few views :( thought I would share! (https://www.youtube.com/watch؟v=Afyqwc96M1Y)
DONE: programming
توجه داشته باشید که اگر این را چند بار اجرا کنید، ترتیب چاپ داده های subreddit تغییر می کند. این به این دلیل است که هر یک از تماسهایی که انجام میدهیم، کنترل رشته را آزاد میکند (بازده) و به تماس HTTP دیگری اجازه میدهد تا process. هر کدام که اول برگردد ابتدا چاپ می شود.
نتیجه
اگرچه عملکرد ناهمزمان داخلی پایتون به خوبی جاوا اسکریپت نیست، اما این بدان معنا نیست که نمی توانید از آن برای برنامه های کاربردی جالب و کارآمد استفاده کنید. فقط 30 دقیقه وقت بگذارید تا نکات و نکات آن را بیاموزید و درک بهتری خواهید داشت که چگونه می توانید این را در برنامه های خود ادغام کنید.
نظر شما در مورد async/wait پایتون چیست؟ در گذشته چگونه از آن استفاده کرده اید؟ در نظرات به ما اطلاع دهید!
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-30 12:04:03