GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing python.github.io — توسعه با asyncio توسعه با asyncio¶برنامهنویسی ناهمگام با برنامهنویسی «ترتیبی» کلاسیک متفاوت است. این صفحه، اشتباهات و تلههای رایج را فهرست میکند و نحوهی اجتناب از آنها را توضیح میدهد. حالت اشکالزدایی¶بهطور پیشفرض، asyncio در حالت تولید اجرا میشود. برای سهولت در توسعه، asyncio یک حالت اشکالزدایی دارد. راههای متعددی برای فعال کردن حالت اشکالزدایی asyncio وجود دارد:
علاوه بر فعال کردن حالت اشکالزدایی، این موارد را نیز در نظر داشته باشید:
هنگامی که حالت اشکالزدایی فعال است:
همروندی و چندنخی¶یک حلقه رویداد در یک نخ (معمولاً نخ اصلی) اجرا میشود و تمام کالبکها و Taskها را در نخ خود اجرا میکند. در حالی که یک Task در حلقه رویداد در حال اجرا است، هیچ Task دیگری نمیتواند در همان نخ اجرا شود. هنگامی که یک Task یک عبارت برای زمانبندی یک کالبک از یک نخ دیگر سیستمعامل، باید از متد loop.call_soon_threadsafe(callback, *args) تقریباً همهی اشیای asyncio ایمن از نظر نخ نیستند، که این موضوع معمولاً مشکلی ایجاد نمیکند، مگر اینکه کدی از خارج از یک Task یا کالبک با آنها کار کند. اگر لازم باشد چنین کدی یک API سطح پایین asyncio را فراخوانی کند، باید از متد loop.call_soon_threadsafe(fut.cancel) برای زمانبندی یک شیء همروال از یک نخ سیستمعاملی دیگر، باید از تابع async def coro_func(): return await asyncio.sleep(1, 42) # Later in another OS thread: future = asyncio.run_coroutine_threadsafe(coro_func(), loop) # Wait for the result: result = future.result() برای مدیریت سیگنالها، حلقه رویداد باید در نخ اصلی اجرا شود. میتوان از متد در حال حاضر هیچ راهی برای زمانبندی همروالها یا کالبکها مستقیماً از یک فرایند دیگر وجود ندارد (مانند فرایندی که با اجرای کد مسدودکننده¶کد مسدودکننده (CPU-bound) نباید بهصورت مستقیم فراخوانی شود. برای مثال، اگر تابعی یک محاسبهی سنگین از نظر CPU را به مدت ۱ ثانیه انجام دهد، تمام Taskهای همزمان asyncio و عملیاتهای IO به اندازهی ۱ ثانیه به تأخیر میافتند. میتوان از یک اجراکننده (executor) برای اجرای یک تکلیف در نخی دیگر، از جمله در مفسری دیگر، یا حتی در فرایندی دیگر استفاده کرد تا از مسدود شدن نخ سیستمعاملِ حلقه رویداد جلوگیری شود. برای جزئیات بیشتر، متد گزارشگیری¶asyncio از ماژول سطح گزارش پیشفرض logging.getLogger("asyncio").setLevel(logging.WARNING) گزارشگیری شبکه میتواند حلقه رویداد را مسدود کند. توصیه میشود برای پردازش گزارشها از یک نخ جداگانه استفاده کنید یا از ورودی/خروجی غیرمسدودکننده (non-blocking IO) استفاده کنید. برای مثال، مدیریت هندلرهایی که مسدود میکنند را ببینید. تشخیص همروالهایی که هرگز await نشدهاند¶هنگامی که یک تابع همروال فراخوانی میشود، اما await نمیشود (برای مثال import asyncio async def test(): print("never scheduled") async def main(): test() asyncio.run(main()) خروجی: test.py:7: RuntimeWarning: coroutine 'test' was never awaited test() خروجی در حالت اشکالزدایی: test.py:7: RuntimeWarning: coroutine 'test' was never awaited Coroutine created at (most recent call last) File "../t.py", line 9, in <module> asyncio.run(main(), debug=True) < .. > File "../t.py", line 7, in main test() test() راهحل معمول این است که یا همروال را await کنید یا تابع async def main(): await test() تشخیص استثناهای هرگز بازیابینشده¶اگر مثالی از یک استثنای مدیریتنشده: import asyncio async def bug(): raise Exception("not consumed") async def main(): asyncio.create_task(bug()) asyncio.run(main()) خروجی: Task exception was never retrieved future: <Task finished coro=<bug() done, defined at test.py:3> exception=Exception('not consumed')> Traceback (most recent call last): File "test.py", line 4, in bug raise Exception("not consumed") Exception: not consumed حالت اشکالزدایی را فعال کنید تا ردگیری پشتهی محل ایجاد وظیفه را دریافت کنید: asyncio.run(main(), debug=True) خروجی در حالت اشکالزدایی: Task exception was never retrieved future: <Task finished coro=<bug() done, defined at test.py:3> exception=Exception('not consumed') created at asyncio/tasks.py:321> source_traceback: Object created at (most recent call last): File "../t.py", line 9, in <module> asyncio.run(main(), debug=True) < .. > Traceback (most recent call last): File "../t.py", line 4, in bug raise Exception("not consumed") Exception: not consumed بهترین شیوههای تولیدگرهای ناهمگام¶نوشتن کد asyncio صحیح و کارآمد، نیازمند آگاهی از برخی دامها است. این بخش بهترین شیوههای ضروری را شرح میدهد که میتواند شما را از ساعتها اشکالزدایی نجات دهد. تولیدگرهای ناهمگام را بهصورت صریح ببندید¶توصیه میشود تولیدگر ناهمگام را بهصورت دستی ببندید. اگر یک تولیدگر زودتر خارج شود، برای مثال، به دلیل پرتاب شدن یک استثنا در بدنهی یک حلقه برای جلوگیری از این موضوع، تولیدگر را با فراخوانی متد import asyncio import contextlib async def gen(): yield 1 yield 2 async def func(): async with contextlib.aclosing(gen()) as g: async for x in g: break # Don't iterate until the end asyncio.run(func()) همانطور که در بالا ذکر شد، کد پاکسازی برای این تولیدگرهای ناهمگام به تعویق میافتد. مثال زیر نشان میدهد که نهاییسازی یک تولیدگر ناهمگام میتواند با ترتیبی غیرمنتظره رخ دهد: import asyncio work_done = False async def cursor(): try: yield 1 finally: assert work_done async def rows(): global work_done try: yield 2 finally: await asyncio.sleep(0.1) # imitate some async work work_done = True async def main(): async for c in cursor(): async for r in rows(): break break asyncio.run(main()) برای این مثال، خروجی زیر را دریافت میکنیم: unhandled exception during asyncio.run() shutdown task: <Task finished name='Task-3' coro=<<async_generator_athrow without __name__>()> exception=AssertionError()> Traceback (most recent call last): File "example.py", line 6, in cursor yield 1 asyncio.exceptions.CancelledError During handling of the above exception, another exception occurred: Traceback (most recent call last): File "example.py", line 8, in cursor assert work_done ^^^^^^^^^ AssertionError تولیدگر ناهمگام این مثال را میتوان با بستن صریح تولیدگرهای ناهمگام async def main(): async with contextlib.aclosing(cursor()) as cursor_gen: async for c in cursor_gen: async with contextlib.aclosing(rows()) as rows_gen: async for r in rows_gen: break break تولیدگرهای ناهمگام را فقط زمانی ایجاد کنید که حلقه رویداد در حال اجرا است¶توصیه میشود تولیدگرهای ناهمگام تنها پس از ایجاد حلقه رویداد ایجاد شوند. برای اطمینان از اینکه تولیدگرهای ناهمگام بهطور قابلاطمینان بسته شوند، حلقه رویداد از تابع هنگامی که تابع تولیدگر ناهمگام، قلاب سیستم مربوطه را در نخستین تکرار خود فراخوانی میکند. در همان زمان، تولیدگر ثبت میکند که قلاب فراخوانی شده است و دیگر آن را فراخوانی نمیکند. بنابراین، اگر تکرار پیش از ایجاد حلقه رویداد آغاز شود، حلقه رویداد نمیتواند تولیدگر را به فهرست تولیدگرهای فعال خود اضافه کند، زیرا قلابها پس از تلاش تولیدگر برای فراخوانی آنها تنظیم میشوند. در نتیجه، حلقه رویداد در صورت لزوم نمیتواند تولیدگر را خاتمه دهد. مثال زیر را در نظر بگیرید: import asyncio async def agenfn(): try: yield 10 finally: await asyncio.sleep(0) with asyncio.Runner() as runner: agen = agenfn() print(runner.run(anext(agen))) del agen خروجی: 10 Exception ignored while closing generator <async_generator object agenfn at 0x000002F71CD10D70>: Traceback (most recent call last): File "example.py", line 13, in <module> del agen ^^^^ RuntimeError: async generator ignored GeneratorExit این مثال را میتوان بهصورت زیر اصلاح کرد: import asyncio async def agenfn(): try: yield 10 finally: await asyncio.sleep(0) async def main(): agen = agenfn() print(await anext(agen)) del agen asyncio.run(main()) از پیمایش و بستن همزمان یک تولیدگر یکسان خودداری کنید¶تولیدگرهای ناهمگام ممکن است در حالی که فراخوانی دیگری از مثال زیر را در نظر بگیرید: import asyncio async def consumer(): for idx in range(100): await asyncio.sleep(0) message = yield idx print('received', message) async def amain(): agenerator = consumer() await agenerator.asend(None) fa = asyncio.create_task(agenerator.asend('A')) fb = asyncio.create_task(agenerator.asend('B')) await fa await fb asyncio.run(amain()) خروجی: received A Traceback (most recent call last): File "test.py", line 38, in <module> asyncio.run(amain()) ~~~~~~~~~~~^^^^^^^^^ File "Lib/asyncio/runners.py", line 204, in run return runner.run(main) ~~~~~~~~~~^^^^^^ File "Lib/asyncio/runners.py", line 127, in run return self._loop.run_until_complete(task) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ File "Lib/asyncio/base_events.py", line 719, in run_until_complete return future.result() ~~~~~~~~~~~~~~~ File "test.py", line 36, in amain await fb RuntimeError: anext(): asynchronous generator is already running بنابراین، توصیه میشود از استفاده از تولیدگرهای ناهمگام در وظایف موازی یا بین چندین حلقه رویداد خودداری کنید.
© حق نشر 2001 Python Software Foundation.
این صفحه تحت مجوز بنیاد نرمافزار پایتون نسخه ۲ منتشر شده است. مثالها، دستورالعملها، و سایر کدهای موجود در مستندات همچنین تحت مجوز بدون بند BSD منتشر شدهاند. برای اطلاعات بیشتر به تاریخچه و مجوز مراجعه کنید. بنیاد نرمافزار پایتون یک شرکت غیرانتفاعی است. لطفاً کمک مالی کنید. آخرین بهروزرسانی در نوامبر 12, 2026 (06:19 UTC). آیا اشکالی یافتید؟ ساخته شده با Sphinx 9.1.0. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |