Python đa luồng cho vòng lặp

Theo mặc định, asyncio chạy ở chế độ sản xuất. Để dễ dàng phát triển, asyncio có chế độ gỡ lỗi

Có một số cách để bật chế độ gỡ lỗi asyncio

  • Đặt biến môi trường thành

    loop.call_soon_threadsafe(callback, *args)
    
    4

  • Sử dụng

  • Vượt qua

    loop.call_soon_threadsafe(callback, *args)
    
    5 đến

  • gọi

Ngoài việc bật chế độ gỡ lỗi, hãy xem xét thêm

  • đặt mức nhật ký của thành

    loop.call_soon_threadsafe(callback, *args)
    
    8, ví dụ: đoạn mã sau có thể được chạy khi khởi động ứng dụng

    logging.basicConfig(level=logging.DEBUG)
    

  • định cấu hình mô-đun để hiển thị cảnh báo. Một cách để làm điều đó là sử dụng tùy chọn dòng lệnh

    loop.call_soon_threadsafe(fut.cancel)
    
    2

Khi chế độ gỡ lỗi được bật

  • asyncio kiểm tra và ghi lại chúng;

  • Nhiều API asyncio không an toàn theo luồng (chẳng hạn như và các phương thức) đưa ra một ngoại lệ nếu chúng được gọi từ một luồng sai

  • Thời gian thực hiện của bộ chọn I/O được ghi lại nếu mất quá nhiều thời gian để thực hiện thao tác I/O

  • Các cuộc gọi lại mất hơn 100 mili giây được ghi lại. Thuộc tính

    loop.call_soon_threadsafe(fut.cancel)
    
    5 có thể được sử dụng để đặt thời lượng thực hiện tối thiểu tính bằng giây được coi là "chậm"

Đồng thời và đa luồng

Một vòng lặp sự kiện chạy trong một luồng (thường là luồng chính) và thực thi tất cả các lệnh gọi lại và Tác vụ trong luồng của nó. Khi một Tác vụ đang chạy trong vòng lặp sự kiện, không có Tác vụ nào khác có thể chạy trong cùng một luồng. Khi một Tác vụ thực thi một biểu thức

loop.call_soon_threadsafe(fut.cancel)
6, Tác vụ đang chạy sẽ bị treo và vòng lặp sự kiện sẽ thực thi Tác vụ tiếp theo

Để lên lịch từ một chuỗi hệ điều hành khác, nên sử dụng phương thức. Ví dụ

loop.call_soon_threadsafe(callback, *args)

Hầu như tất cả các đối tượng asyncio không phải là luồng an toàn, đây thường không phải là vấn đề trừ khi có mã hoạt động với chúng từ bên ngoài Tác vụ hoặc gọi lại. Nếu cần mã như vậy để gọi API asyncio cấp thấp, phương pháp này nên được sử dụng, e. g

loop.call_soon_threadsafe(fut.cancel)

Để lên lịch cho một đối tượng coroutine từ một chuỗi hệ điều hành khác, nên sử dụng chức năng này. Nó trả về a để truy cập kết quả

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()

Để xử lý các tín hiệu và thực thi các quy trình con, vòng lặp sự kiện phải được chạy trong luồng chính

Phương pháp này có thể được sử dụng với a để thực thi mã chặn trong một chuỗi hệ điều hành khác mà không chặn chuỗi hệ điều hành mà vòng lặp sự kiện chạy trong đó

Hiện tại không có cách nào để lên lịch cho coroutine hoặc gọi lại trực tiếp từ một quy trình khác (chẳng hạn như quy trình bắt đầu bằng ). Phần liệt kê các API có thể đọc từ đường ống và xem bộ mô tả tệp mà không chặn vòng lặp sự kiện. Ngoài ra, các API của asyncio cung cấp một cách để bắt đầu một quy trình và giao tiếp với nó từ vòng lặp sự kiện. Cuối cùng, phương pháp nói trên cũng có thể được sử dụng với a để thực thi mã trong một quy trình khác

Chạy mã chặn

Không nên gọi trực tiếp mã chặn (liên kết với CPU). Ví dụ: nếu một hàm thực hiện phép tính sử dụng nhiều CPU trong 1 giây, thì tất cả các tác vụ IO và Tác vụ không đồng bộ đồng thời sẽ bị trễ 1 giây

Một bộ thực thi có thể được sử dụng để chạy một tác vụ trong một luồng khác hoặc thậm chí trong một quy trình khác để tránh chặn luồng hệ điều hành bằng vòng lặp sự kiện. Xem phương pháp để biết thêm chi tiết

ghi nhật ký

asyncio sử dụng mô-đun và tất cả việc ghi nhật ký được thực hiện thông qua trình ghi nhật ký

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()
8

Mức nhật ký mặc định là

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()
9, có thể dễ dàng điều chỉnh

logging.getLogger("asyncio").setLevel(logging.WARNING)

Ghi nhật ký mạng có thể chặn vòng lặp sự kiện. Bạn nên sử dụng một luồng riêng để xử lý nhật ký hoặc sử dụng IO không chặn. Ví dụ, xem

Phát hiện các coroutine không bao giờ chờ đợi

Khi một chức năng coroutine được gọi, nhưng không được chờ đợi (e. g.

logging.getLogger("asyncio").setLevel(logging.WARNING)
0 thay vì
logging.getLogger("asyncio").setLevel(logging.WARNING)
1) hoặc coroutine không được lên lịch với , asyncio sẽ phát ra một

import asyncio

async def test():
    print("never scheduled")

async def main():
    test()

asyncio.run(main())

đầu ra

test.py:7: RuntimeWarning: coroutine 'test' was never awaited
  test()

Đầu ra ở chế độ gỡ lỗi

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()

Cách khắc phục thông thường là đợi coroutine hoặc gọi hàm

async def main():
    await test()

Phát hiện các ngoại lệ không bao giờ truy xuất

Nếu a được gọi nhưng đối tượng Tương lai không bao giờ được chờ đợi, thì ngoại lệ sẽ không bao giờ được truyền tới mã người dùng. Trong trường hợp này, asyncio sẽ phát ra thông báo nhật ký khi đối tượng Tương lai được thu gom rác