Hướng dẫn python-trio - python-bộ ba

Chào mừng bạn đến với hướng dẫn bộ ba! Trio là một thư viện Python hiện đại để viết các ứng dụng không đồng bộ - nghĩa là các chương trình muốn làm nhiều việc cùng một lúc với I/O song song, giống như một con nhện web có được nhiều trang song song, một máy chủ web đang tung hứng rất nhiều Tải xuống loại đó. Ở đây, chúng tôi sẽ cố gắng giới thiệu nhẹ nhàng về lập trình không đồng bộ với bộ ba.

Chúng tôi cho rằng bạn đã quen thuộc với Python nói chung, nhưng đừng lo lắng - chúng tôi không cho rằng bạn biết bất cứ điều gì về chương trình không đồng bộ hoặc tính năng

import trio

async def double_sleep[x]:
    await trio.sleep[2 * x]

trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
5 mới của Python.

Ngoài ra, không giống như nhiều hướng dẫn

import trio

async def double_sleep[x]:
    await trio.sleep[2 * x]

trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
5, chúng tôi cho rằng mục tiêu của bạn là sử dụng bộ ba để viết các chương trình thú vị, vì vậy chúng tôi đã giành chiến thắng trong các chi tiết nitty-gritty về cách
import trio

async def double_sleep[x]:
    await trio.sleep[2 * x]

trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
5 được triển khai bên trong phiên dịch Python. Từ Cor Coroutine không bao giờ được đề cập. Thực tế là, bạn thực sự không cần phải biết bất kỳ thứ gì trong số đó trừ khi bạn muốn thực hiện một thư viện như Trio, vì vậy chúng tôi bỏ nó ra [mặc dù chúng tôi sẽ ném vào một vài liên kết cho những người muốn đào sâu hơn].

Được rồi, đã sẵn sàng? Bắt đầu nào.

Trước khi bắt đầu¶

  1. Hãy chắc chắn rằng bạn đã sử dụng Python 3.7 hoặc mới hơn.

  2. import trio
    
    async def double_sleep[x]:
        await trio.sleep[2 * x]
    
    trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
    
    8 [hoặc trên Windows, có thể
    import trio
    
    async def double_sleep[x]:
        await trio.sleep[2 * x]
    
    trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
    
    9 - chi tiết]

  3. Bạn có thể

    trio.run -> double_sleep -> trio.sleep
    
    0? Nếu vậy thì bạn rất tốt để đi!

Nếu bạn bị lạc hoặc bối rối… ¶

Sau đó, chúng tôi muốn biết! Chúng tôi có một kênh trò chuyện thân thiện, bạn có thể đặt câu hỏi bằng cách sử dụng thẻ python-trio, trên stackoverflow hoặc chỉ gửi lỗi [nếu tài liệu của chúng tôi khó hiểu, đó là lỗi của chúng tôi và chúng tôi muốn sửa nó!].

Chức năng không đồng bộ

Python 3.5 đã thêm một tính năng mới: các chức năng Async. Sử dụng bộ ba là tất cả về việc viết các chức năng Async, vì vậy hãy để bắt đầu từ đó.

Hàm async được xác định như hàm bình thường, ngoại trừ bạn viết

trio.run -> double_sleep -> trio.sleep
1 thay vì
trio.run -> double_sleep -> trio.sleep
2:

# A regular function
def regular_double[x]:
    return 2 * x

# An async function
async def async_double[x]:
    return 2 * x

Voi Async là viết tắt của người Viking không đồng bộ; Đôi khi, chúng tôi đề cập đến các chức năng thường xuyên như

trio.run -> double_sleep -> trio.sleep
3 là các hàm đồng bộ của Hồi giáo, để phân biệt chúng với các hàm async.

Từ quan điểm của người dùng, có hai sự khác biệt giữa hàm async và chức năng chính quy:

  1. Để gọi hàm Async, bạn phải sử dụng từ khóa

    trio.run -> double_sleep -> trio.sleep
    
    4. Vì vậy, thay vì viết
    trio.run -> double_sleep -> trio.sleep
    
    5, bạn viết
    trio.run -> double_sleep -> trio.sleep
    
    6.

  2. Bạn có thể sử dụng từ khóa

    trio.run -> double_sleep -> trio.sleep
    
    4 bên trong phần thân của chức năng thông thường. Nếu bạn thử nó, bạn sẽ gặp lỗi cú pháp:

    def print_double[x]:
        print[await async_double[x]]   #  double_sleep -> trio.sleep
    
    4 được cho phép:

    async def print_double[x]:
        print[await async_double[x]]   #  double_sleep -> trio.sleep
    
    4 để gọi hàm Async và chỉ các hàm Async mới có thể sử dụng ____ 54 ở đây, một bảng nhỏ:

    Nếu một chức năng như thế này

    muốn gọi một chức năng như thế này

    Nó sẽ xảy ra?

    đồng bộ hóa

    đồng bộ hóa

    đồng bộ hóa

    không đồng bộ

    đồng bộ hóa

    không đồng bộ

    KHÔNG

    Vì vậy, Tóm lại: với tư cách là người dùng, toàn bộ lợi thế của các hàm Async so với các chức năng thông thường là các chức năng Async có siêu năng lực: họ có thể gọi các chức năng Async khác.

    Điều này ngay lập tức đặt ra hai câu hỏi: làm thế nào, và tại sao? Đặc biệt:

    Khi chương trình Python của bạn bắt đầu, nó chạy mã đồng bộ hóa cũ thông thường. Vì vậy, có một vấn đề về gà và trứng: một khi chúng ta đang chạy một chức năng Async, chúng ta có thể gọi các chức năng Async khác, nhưng làm thế nào để chúng ta gọi hàm Async đầu tiên đó?

    1. Và, nếu lý do duy nhất để viết một hàm Async là nó có thể gọi các chức năng Async khác, tại sao chúng ta lại sử dụng chúng ngay từ đầu? Ý tôi là, khi siêu năng lực đi, điều này có vẻ hơi vô nghĩa. Sẽ đơn giản hơn khi chỉ cần sử dụng bất kỳ chức năng ASYNC nào?

      import trio
      
      async def async_double[x]:
          return 2 * x
      
      trio.run[async_double, 3]  # returns 6
      

      Đây là nơi một thư viện Async như Trio xuất hiện. Nó cung cấp hai điều:

    2. Một hàm chạy, là một hàm đồng bộ đặc biệt lấy và gọi một hàm không đồng bộ. Trong bộ ba, đây là

      trio.run -> [async function] -> ... -> [async function] -> trio.whatever
      
      1:

      Vì vậy, câu trả lời cho các phần của người Viking.

      import trio
      
      async def double_sleep[x]:
          await trio.sleep[2 * x]
      
      trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
      

    Một loạt các chức năng Async hữu ích - đặc biệt là các chức năng để thực hiện I/O. Vì vậy, câu trả lời cho các vấn đề tại sao: các chức năng này là async và chúng rất hữu ích, vì vậy nếu bạn muốn sử dụng chúng, bạn phải viết mã async. Nếu bạn nghĩ rằng việc theo dõi những

    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    2 và
    trio.run -> double_sleep -> trio.sleep
    
    4 này thật khó chịu, thì quá tệ - bạn đã không có lựa chọn nào khác trong vấn đề này! .

    trio.run -> double_sleep -> trio.sleep
    

    This “sandwich” structure is typical for async code; in general, it looks like:

    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    

    It’s exactly the functions on the path between

    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 and
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    1 that have to be async. Trio provides the async bread, and then your code makes up the async sandwich’s tasty async filling. Other functions [e.g., helpers you call along the way] should generally be regular, non-async functions.

    Warning: don’t forget that
    trio.run -> double_sleep -> trio.sleep
    
    4!¶

    Now would be a good time to open up a Python prompt and experiment a little with writing simple async functions and running them with

    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    1.

    At some point in this process, you’ll probably write some code like this, that tries to call an async function but leaves out the

    trio.run -> double_sleep -> trio.sleep
    
    4:

    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    

    You might think that Python would raise an error here, like it does for other kinds of mistakes we sometimes make when calling a function. Like, if we forgot to pass

    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    5 its required argument, then we would get a nice
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    6 saying so. But unfortunately, if you forget an
    trio.run -> double_sleep -> trio.sleep
    
    4, you don’t get that. What you actually get is:

    >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    __main__:4: RuntimeWarning: coroutine 'sleep' was never awaited
    >>>
    

    This is clearly broken – 0.00 seconds is not long enough to feel well rested! Yet the code acts like it succeeded – no exception was raised. The only clue that something went wrong is that it prints

    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    8. Also, the exact place where the warning is printed might vary, because it depends on the whims of the garbage collector. If you’re using PyPy, you might not even get a warning at all until the next GC collection runs:

    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    

    [If you can’t see the warning above, try scrolling right.]

    Forgetting an

    trio.run -> double_sleep -> trio.sleep
    
    4 like this is an incredibly common mistake. You will mess this up. Everyone does. And Python will not help you as much as you’d hope 😞. The key thing to remember is: if you see the magic words
    >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    __main__:4: RuntimeWarning: coroutine 'sleep' was never awaited
    >>>
    
    0, then this always means that you made the mistake of leaving out an
    trio.run -> double_sleep -> trio.sleep
    
    4 somewhere, and you should ignore all the other error messages you see and go fix that first, because there’s a good chance the other stuff is just collateral damage. I’m not even sure what all that other junk in the PyPy output is. Fortunately I don’t need to know, I just need to fix my function!

    [“I thought you said you weren’t going to mention coroutines!” Yes, well, I didn’t mention coroutines, Python did. Take it up with Guido! But seriously, this is unfortunately a place where the internal implementation details do leak out a bit.]

    Why does this happen? In Trio, every time we use

    trio.run -> double_sleep -> trio.sleep
    
    4 it’s to call an async function, and every time we call an async function we use
    trio.run -> double_sleep -> trio.sleep
    
    4. But Python’s trying to keep its options open for other libraries that are ahem a little less organized about things. So while for our purposes we can think of
    >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    __main__:4: RuntimeWarning: coroutine 'sleep' was never awaited
    >>>
    
    4 as a single piece of syntax, Python thinks of it as two things: first a function call that returns this weird “coroutine” object:

    def print_double[x]:
        print[await async_double[x]]   #  double_sleep -> trio.sleep
    
    4, which actually runs the function. So if you forget
    trio.run -> double_sleep -> trio.sleep
    
    4, then two bad things happen: your function doesn’t actually get called, and you get a “coroutine” object where you might have been expecting something else, like a number:

    def print_double[x]:
        print[await async_double[x]]   #  double_sleep -> trio.sleep
    
    4, or an extra
    trio.run -> double_sleep -> trio.sleep
    
    4, and see what you get. This way you’ll be prepared for when it happens to you for real.

    And remember: watch out for

    >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    __main__:4: RuntimeWarning: coroutine 'sleep' was never awaited
    >>>
    
    9; it means you need to find and fix your missing
    trio.run -> double_sleep -> trio.sleep
    
    4.

    Okay, let’s see something cool already¶

    So now we’ve started using Trio, but so far all we’ve learned to do is write functions that print things and sleep for various lengths of time. Interesting enough, but we could just as easily have done that with

    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    7.
    import trio
    
    async def double_sleep[x]:
        await trio.sleep[2 * x]
    
    trio.run[double_sleep, 3]  # does nothing for 6 seconds then returns
    
    5 is useless!

    Well, not really. Trio has one more trick up its sleeve, that makes async functions more powerful than regular functions: it can run multiple async functions at the same time. Here’s an example:

    def print_double[x]:
        print[await async_double[x]]   # >> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 and
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4. These should look familiar from the last section:

    def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 as an async function that’s going to call
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 and
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4 concurrently:

    def print_double[x]:
        print[await async_double[x]]   # >> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 statement to create a “nursery”, and then “spawns”
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 and
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4 into the nursery.

    Let’s start with this

    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 thing. It’s actually pretty simple. In regular Python, a statement like
    def print_double[x]:
        print[await async_double[x]]   # >> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 statement calls async methods: at the start of the block it does
    def print_double[x]:
        print[await async_double[x]]   # >>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8.

    Ghi chú

    Ví dụ này không sử dụng chúng, nhưng trong khi chúng tôi ở đây, chúng tôi cũng có thể đề cập đến một phần cú pháp mới khác mà Async/đang chờ thêm vào:

    def print_double[x]:
        print[await async_double[x]]   # >>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8, hãy để Lừa nhìn vào
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 một lần nữa:

    def print_double[x]:
        print[await async_double[x]]   # > trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 mà chúng tôi gọi là
    def print_double[x]:
        print[await async_double[x]]   #  trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 và
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4 hiện đang chạy trong nền. Và sau đó ở dòng 25, dòng nhận xét, chúng tôi đã đạt đến cuối khối ____998 và chức năng
    def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 để có được một vườn ươm: nó cho chúng tôi một cách để đảm bảo rằng đứa trẻ gọi có thể chạy trốn và bị lạc. Một lý do điều này rất quan trọng là nếu có một lỗi hoặc vấn đề khác ở một trong những đứa trẻ, và nó sẽ đặt ra một ngoại lệ, thì nó cho phép chúng ta tuyên truyền ngoại lệ đó vào cha mẹ; Trong nhiều khung khác, các trường hợp ngoại lệ như thế này chỉ bị loại bỏ. Bộ ba không bao giờ loại bỏ ngoại lệ.

    Được! Hãy để thử chạy nó và xem những gì chúng ta nhận được:

    def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 và
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4 đều bắt đầu cùng nhau và sau đó cả hai thoát ra cùng nhau. Và, mặc dù chúng tôi đã thực hiện hai cuộc gọi đến
    def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 và
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4 thực sự đang chạy cùng một lúc!

    Bây giờ, nếu bạn quen thuộc với lập trình bằng cách sử dụng các chủ đề, điều này có thể trông quen thuộc - và đó là cố ý. Nhưng điều quan trọng là phải nhận ra rằng không có chủ đề ở đây. Tất cả điều này đang xảy ra trong một chủ đề duy nhất. Để nhắc nhở bản thân về điều này, chúng tôi sử dụng thuật ngữ hơi khác nhau: thay vì sinh sản hai chủ đề của người Hồi giáo, chúng tôi nói rằng chúng tôi đã sinh ra hai nhiệm vụ của Hồi giáo. Có hai sự khác biệt giữa các tác vụ và luồng: [1] Nhiều tác vụ có thể thay phiên nhau chạy trên một luồng và [2] với các luồng, trình thông dịch Python/hệ điều hành có thể chuyển đổi luồng nào đang chạy bất cứ khi nào chúng cảm thấy thích nó; Với các nhiệm vụ, chúng tôi chỉ có thể chuyển đổi ở một số địa điểm được chỉ định nhất định mà chúng tôi gọi là điểm kiểm tra. Trong phần tiếp theo, chúng tôi sẽ đào sâu vào ý nghĩa của điều này.“checkpoints”. In the next section, we’ll dig into what this means.

    Chuyển đổi nhiệm vụ minh họa Or

    Ý tưởng lớn đằng sau các thư viện dựa trên Async/đang chờ đợi như Trio là chạy đồng thời nhiều tác vụ trên một luồng bằng cách chuyển đổi giữa chúng tại các địa điểm thích hợp-ví dụ, nếu chúng ta đang triển khai một máy chủ web, thì một tác vụ có thể gửi Phản hồi HTTP cùng lúc với một nhiệm vụ khác đang chờ các kết nối mới. Nếu tất cả những gì bạn muốn làm là sử dụng bộ ba, thì bạn không cần phải hiểu tất cả các chi tiết nitty-gritty về cách chuyển đổi này hoạt động-nhưng rất hữu ích khi có ít nhất một trực giác chung về những gì bộ ba đang làm Khi mã của bạn được thực thi. Để giúp xây dựng trực giác đó, hãy để Lôi xem xét kỹ hơn về cách Trio chạy ví dụ của chúng tôi từ phần cuối cùng.

    May mắn thay, bộ ba cung cấp một bộ công cụ phong phú để kiểm tra và gỡ lỗi các chương trình của bạn. Ở đây chúng tôi muốn xem

    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 tại nơi làm việc, mà chúng tôi có thể làm bằng cách viết một lớp mà chúng tôi sẽ gọi là
    def print_double[x]:
        print[await async_double[x]]   # >>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 và bạn có thể thấy
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 tạo ra hai nhiệm vụ trẻ em. Sau đó, nó đánh vào cuối khối
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 và tạm dừng:

    async def print_double[x]:
        print[await async_double[x]]   #  [async function] -> trio.whatever
    
    5, và rồi đột nhiên chúng tôi quay lại trong
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 quyết định những gì sẽ chạy tiếp theo. Làm thế nào điều này xảy ra? Bí quyết là
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 và
    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    5 hợp tác để thực hiện nó:
    trio.run -> [async function] -> ... -> [async function] -> trio.whatever
    
    5 có quyền truy cập vào một số phép thuật đặc biệt cho phép nó tự tạm dừng, do đó, nó gửi một ghi chú đến
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 yêu cầu đánh thức lại sau 1 giây, sau đó đình chỉ nhiệm vụ. Và một khi nhiệm vụ bị đình chỉ, Python sẽ kiểm soát trở lại
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0, quyết định phải làm gì tiếp theo. .

    Ghi chú

    Bạn có thể tự hỏi liệu bạn có thể kết hợp các nguyên thủy từ các thư viện Async khác nhau hay không. Ví dụ, chúng ta có thể sử dụng

    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 cùng với
    def print_double[x]:
        print[await async_double[x]]   #  double_sleep -> trio.sleep
    
    4 trên đó, thì bạn biết rằng nó có thể là nơi mà nhiệm vụ của bạn sẽ bị đình chỉ. Điều này làm cho các nhiệm vụ dễ lý luận hơn nhiều so với các chủ đề, bởi vì có rất nhiều cách mà các nhiệm vụ có thể được xen kẽ với nhau và dẫm lên trạng thái của nhau. .further guarantees beyond that, but that’s the big one.

    Và bây giờ bạn cũng biết lý do tại sao

    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 phải sử dụng
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 để mở vườn ươm: Nếu chúng tôi đã sử dụng một khối
    def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    8 mang lại cho chúng ta.

    Bây giờ, trở lại điểm thực thi của chúng tôi. Tóm lại: Tại thời điểm này

    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 đang chờ đợi trên
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    3 và
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    4, và cả hai đứa trẻ đang ngủ. Vì vậy,
    import time
    import trio
    
    async def broken_double_sleep[x]:
        print["*yawn* Going to sleep"]
        start_time = time.perf_counter[]
    
        # Whoops, we forgot the 'await'!
        trio.sleep[2 * x]
    
        sleep_time = time.perf_counter[] - start_time
        print[f"Woke up after {sleep_time:.2f} seconds, feeling well rested!"]
    
    trio.run[broken_double_sleep, 3]
    
    0 kiểm tra các ghi chú của nó và thấy rằng không có gì phải làm cho đến khi những giấc ngủ đó kết thúc - trừ khi có thể một số sự kiện I/O bên ngoài xuất hiện. Nếu điều đó xảy ra, thì nó có thể cho chúng ta điều gì đó để làm. Tất nhiên, chúng tôi đã thực hiện bất kỳ I/O nào ở đây để nó giành chiến thắng, nhưng trong các tình huống khác, nó có thể. Vì vậy, tiếp theo, nó gọi một hệ điều hành nguyên thủy để đưa toàn bộ quá trình vào giấc ngủ:

    async def print_double[x]:
        print[await async_double[x]]   #  [async function] -> ... -> [async function] -> trio.whatever
    
    5 đã gửi nói khi nào hai nhiệm vụ trẻ em nên được đánh thức một lần nữa, và nhận ra rằng họ đã ngủ đủ lâu, vì vậy nó lên lịch cho họ sớm chạy:

    async def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 đang chờ họ kết thúc? Lưu ý cách
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 được lên lịch khi đứa con đầu tiên thoát ra:

    async def print_double[x]:
        print[await async_double[x]]   # >>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 thức dậy. Mã dọn dẹp vườn ươm thông báo rằng tất cả trẻ em của nó đã thoát ra, và cho phép khối nhà trẻ kết thúc. Và sau đó
    # On PyPy:
    >>>> trio.run[broken_double_sleep, 3]
    *yawn* Going to sleep
    Woke up after 0.00 seconds, feeling well rested!
    >>>> # what the ... ?? not even a warning!
    
    >>>> # but forcing a garbage collection gives us a warning:
    >>>> import gc
    >>>> gc.collect[]
    /home/njs/pypy-3.8-nightly/lib-python/3/importlib/_bootstrap.py:191: RuntimeWarning: coroutine 'sleep' was never awaited
    if _module_locks.get[name] is wr:    # XXX PyPy fix?
    0
    >>>>
    
    5 tạo ra một bản in cuối cùng và thoát:

    async def print_double[x]:
        print[await async_double[x]]   # 

    Bài Viết Liên Quan

    Chủ Đề