Wrap an event loop to add implementations of the ``add_reader`` method family. Instances of this class start a second thread to run a selector. This thread is completely hidden from the user; all callbacks are run on the wrapped event loop's thread. This class is used automatically
| 688 | |
| 689 | |
| 690 | class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop): |
| 691 | """Wrap an event loop to add implementations of the ``add_reader`` method family. |
| 692 | |
| 693 | Instances of this class start a second thread to run a selector. |
| 694 | This thread is completely hidden from the user; all callbacks are |
| 695 | run on the wrapped event loop's thread. |
| 696 | |
| 697 | This class is used automatically by Tornado; applications should not need |
| 698 | to refer to it directly. |
| 699 | |
| 700 | It is safe to wrap any event loop with this class, although it only makes sense |
| 701 | for event loops that do not implement the ``add_reader`` family of methods |
| 702 | themselves (i.e. ``WindowsProactorEventLoop``) |
| 703 | |
| 704 | Closing the ``AddThreadSelectorEventLoop`` also closes the wrapped event loop. |
| 705 | |
| 706 | """ |
| 707 | |
| 708 | # This class is a __getattribute__-based proxy. All attributes other than those |
| 709 | # in this set are proxied through to the underlying loop. |
| 710 | MY_ATTRIBUTES = { |
| 711 | "_real_loop", |
| 712 | "_selector", |
| 713 | "add_reader", |
| 714 | "add_writer", |
| 715 | "close", |
| 716 | "remove_reader", |
| 717 | "remove_writer", |
| 718 | } |
| 719 | |
| 720 | def __getattribute__(self, name: str) -> Any: |
| 721 | if name in AddThreadSelectorEventLoop.MY_ATTRIBUTES: |
| 722 | return super().__getattribute__(name) |
| 723 | return getattr(self._real_loop, name) |
| 724 | |
| 725 | def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None: |
| 726 | self._real_loop = real_loop |
| 727 | self._selector = SelectorThread(real_loop) |
| 728 | |
| 729 | def close(self) -> None: |
| 730 | self._selector.close() |
| 731 | self._real_loop.close() |
| 732 | |
| 733 | def add_reader( |
| 734 | self, |
| 735 | fd: "_FileDescriptorLike", |
| 736 | callback: Callable[..., None], |
| 737 | *args: "Unpack[_Ts]", |
| 738 | ) -> None: |
| 739 | return self._selector.add_reader(fd, callback, *args) |
| 740 | |
| 741 | def add_writer( |
| 742 | self, |
| 743 | fd: "_FileDescriptorLike", |
| 744 | callback: Callable[..., None], |
| 745 | *args: "Unpack[_Ts]", |
| 746 | ) -> None: |
| 747 | return self._selector.add_writer(fd, callback, *args) |
no outgoing calls