Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Event-Driven asyncio: A Case Study of Trio's API(PyCon US 2024)

Junya Fukuda
May 18, 2024
48

Event-Driven asyncio: A Case Study of Trio's API(PyCon US 2024)

Description
Asyncio is highly efficient in operating within a single thread, making it exceptionally well-suited for environments with limited resources.
In our product, we leverage Python's asynchronous capabilities to streamline the decision-making processes of our robots. I will individually introduce trio and trio-util, as well as anyio and asyncio, in the presentation.

Session: https://us.pycon.org/2024/schedule/presentation/142/
X: https://x.com/JunyaFff
linkedin: https://www.linkedin.com/in/junya-fukuda-4622a863/

Junya Fukuda

May 18, 2024
Tweet

More Decks by Junya Fukuda

Transcript

  1. Who am I? 👤 •Junya Fukudaʢ@JunyaFffʣcalled “Jun” not “Junior” •Photos

    📷 SNS post 👍 •Software Engineer at Groove X, inc. Here is today's code
  2. Who am I? 👤 •book •Python Practical Recipes Here is

    today's code •Junya Fukudaʢ@JunyaFffʣcalled “Jun” not “Junior” •Photos 📷 SNS post 👍 •Software Engineer at Groove X, inc.
  3. Who am I? 👤 •Expert Python Programming - Fourth Edition

    •Written by Tarek Ziadé, Michał Jaworski Here is today's code •Junya Fukudaʢ@JunyaFffʣcalled “Jun” not “Junior” •Photos 📷 SNS post 👍 •Software Engineer at Groove X, inc. •book •Python Practical Recipes
  4. Who am I? 👤 •Expert Python Programming - Fourth Edition

    •Written by Tarek Ziadé, Michał Jaworski •Junya Fukudaʢ@JunyaFffʣcalled “Jun” not “Junior” •Photos 📷 SNS post 👍 •Software Engineer at Groove X, inc. •book •Python Practical Recipes Here is today's code
  5. Today's Goal •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs
  6. Today's Goal •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •About Trio and Trio-util, asyncio
  7. Today's Goal •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •About Trio and Trio-util, asyncio AsyncValue class
  8. Today's Goal •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •About Trio and Trio-util, asyncio AsyncValue class •Handling Many Inputs in Async Apps - AsyncValue
  9. Today's Goal •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •About Trio and Trio-util, asyncio AsyncValue class •Handling Many Inputs in Async Apps - AsyncValue 🌷
  10. Today's Agenda •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs
  11. Today's Agenda •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •Why Python Async •Why Trio
  12. Today's Agenda •Python async and robot use case •Event-Driven Example

    in Robot Development - Handling Multiple Inputs •Why Python Async •Why Trio
  13. Why Python Async •Their name is LOVOT •Over 10,000 sold

    in Japan •Equipped with many sensors
  14. Why Python Async •Their name is LOVOT •Over 10,000 sold

    in Japan •Equipped with many sensors •Decision-Making and Environment
  15. Why Python Async •Equipped with many sensors - many I/O

    •Limited HW resources • Python Async is perfect
  16. Why Trio? •Robust cancellation •Structured Concurrency •User-friendly API No high-level

    APIs yet 😢 •However, this decision was made in the summer of 2017
  17. Why Trio? •Why do we need a user-friendly APIʁ •Animators

    also needed to write code. 8F DIPTF 5SJP
  18. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  19. •Continuously watch for value changes 👀 async def main(): async

    with trio.open_nursery() as nursery: event1 = AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“)
  20. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  21. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  22. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  23. •Continuously watch for value changes 👀 async def main(): async

    with trio.open_nursery() as nursery: event1 = AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“)
  24. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  25. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  26. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  27. async def main(): async with trio.open_nursery() as nursery: event1 =

    AsyncValue("idel 🤖😢") event2 = AsyncValue("idel 🤖😆") nursery.start_soon(fetch, event1, event2) with compose_values(event1=event1, event2=event2) as comp_event: async for v in comp_event.eventual_values(): print(f"doing something cute 🤖 {v=}“) •Continuously watch for value changes 👀
  28. class _ValueWrapper: … def __hash__(self): try: return hash(self.value) except TypeError:

    return super().__hash__() def __eq__(self, other): return self.value.__eq__(other.value) def __call__(self, x, *args): return x == self.value •class _ValueWrapper:
  29. class _RefCountedDefaultDict(defaultdict): """defaultdict offering deterministic collection of unreferenced keys""" …

    @contextmanager def open_ref(self, key): try: yield self[key] finally: self.refs_by_key[key] -= 1 if self.refs_by_key[key] == 0: del self[key] del self.refs_by_key[key] •class _RefCountedDefaultDict
  30. Handling Multiple Inputs •Inside AsyncValue •Value Storage and Setting •Waiting

    for Value Changes: •Waiting for Transitions •Iterating Over Transitions •Waiting for Value Changes:
  31. Handling Multiple Inputs •In the case of asyncio: •There is

    no API that performs the same function. •Synchronization Primitives •asyncio.Event, asyncio.Condition
  32. Handling Multiple Inputs •Trio-util does not support anyio yet •There

    is no API that performs the same function. •asyncio-util IUUQTHJUIVCDPNKSGLBTZODJPVUJM Here is today's code
  33. reference •Simplifying Python's Async with Trio •https://talkpython.fm/episodes/show/167/simplifying-pythons-async-with-trio •Higher level Python

    asyncio with AnyIO •https://talkpython.fm/episodes/show/385/higher-level-python-asyncio-with-anyio •groove-x / trio-util •https://github.com/groove-x/trio-util •Structured Concurrency - Martin Sústrik •https://250bpm.com/blog:71/
  34. Groove X will be a sponsor of PyCon JP 2024.

    See you in Tokyo. Sep27-28 2024
  35. Groove X will be a sponsor of PyCon JP 2024.

    See you in Tokyo. Sep27-28 2024
  36. Do you have a any Question? Feel free to ask

    questions on Twitter. (@junya ff f)