Title: Optimize XXXSelector for many iterations of the event loop · Issue #106751 · python/cpython · GitHub
Open Graph Title: Optimize XXXSelector for many iterations of the event loop · Issue #106751 · python/cpython
X Title: Optimize XXXSelector for many iterations of the event loop · Issue #106751 · python/cpython
Description: split out from #106555 (comment) The current EpollSelector can be sped up a bit. This makes quite a difference when there are 100000+ iterations of the event loop per minute (the use case being receiving bluetooth data from multiple sour...
Open Graph Description: split out from #106555 (comment) The current EpollSelector can be sped up a bit. This makes quite a difference when there are 100000+ iterations of the event loop per minute (the use case being rec...
X Description: split out from #106555 (comment) The current EpollSelector can be sped up a bit. This makes quite a difference when there are 100000+ iterations of the event loop per minute (the use case being rec...
Opengraph URL: https://github.com/python/cpython/issues/106751
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Optimize XXXSelector for many iterations of the event loop","articleBody":"split out from https://github.com/python/cpython/pull/106555#issuecomment-1632025959\r\n\r\nThe current `EpollSelector` can be sped up a bit. This makes quite a difference when there are 100000+ iterations of the event loop per minute (the use case being receiving bluetooth data from multiple sources) since selectors have to run every iteration.\r\n\r\noriginal: 11.831302762031555\r\nnew: 9.579423972172663\r\n\r\n```\r\nimport timeit\r\nimport math\r\nimport select\r\nimport os\r\nfrom selectors import EpollSelector, EVENT_WRITE, EVENT_READ\r\n\r\n\r\nclass OriginalEpollSelector(EpollSelector):\r\n def select(self, timeout=None):\r\n if timeout is None:\r\n timeout = -1\r\n elif timeout \u003c= 0:\r\n timeout = 0\r\n else:\r\n # epoll_wait() has a resolution of 1 millisecond, round away\r\n # from zero to wait *at least* timeout seconds.\r\n timeout = math.ceil(timeout * 1e3) * 1e-3\r\n # epoll_wait() expects `maxevents` to be greater than zero;\r\n # we want to make sure that `select()` can be called when no\r\n # FD is registered.\r\n max_ev = max(len(self._fd_to_key), 1)\r\n ready = []\r\n try:\r\n fd_event_list = self._selector.poll(timeout, max_ev)\r\n except InterruptedError:\r\n return ready\r\n for fd, event in fd_event_list:\r\n events = 0\r\n if event \u0026 ~select.EPOLLIN:\r\n events |= EVENT_WRITE\r\n if event \u0026 ~select.EPOLLOUT:\r\n events |= EVENT_READ\r\n\r\n key = self._key_from_fd(fd)\r\n if key:\r\n ready.append((key, events \u0026 key.events))\r\n return ready\r\n\r\n\r\nNOT_EPOLLIN = ~select.EPOLLIN\r\nNOT_EPOLLOUT = ~select.EPOLLOUT\r\n\r\nclass NewEpollSelector(EpollSelector):\r\n def select(self, timeout=None):\r\n if timeout is None:\r\n timeout = -1\r\n elif timeout \u003c= 0:\r\n timeout = 0\r\n else:\r\n # epoll_wait() has a resolution of 1 millisecond, round away\r\n # from zero to wait *at least* timeout seconds.\r\n timeout = math.ceil(timeout * 1e3) * 1e-3\r\n # epoll_wait() expects `maxevents` to be greater than zero;\r\n # we want to make sure that `select()` can be called when no\r\n # FD is registered.\r\n max_ev = len(self._fd_to_key) or 1\r\n ready = []\r\n try:\r\n fd_event_list = self._selector.poll(timeout, max_ev)\r\n except InterruptedError:\r\n return ready\r\n \r\n fd_to_key = self._fd_to_key\r\n for fd, event in fd_event_list:\r\n key = fd_to_key.get(fd)\r\n if key:\r\n ready.append(\r\n (\r\n key,\r\n (\r\n (event \u0026 NOT_EPOLLIN and EVENT_WRITE)\r\n | (event \u0026 NOT_EPOLLOUT and EVENT_READ)\r\n )\r\n \u0026 key.events,\r\n )\r\n )\r\n return ready\r\n\r\n\r\noriginal_epoll = OriginalEpollSelector()\r\nnew_epoll = NewEpollSelector()\r\n\r\n\r\nfor _ in range(512):\r\n r, w = os.pipe()\r\n os.write(w, b\"a\")\r\n original_epoll.register(r, EVENT_READ)\r\n new_epoll.register(r, EVENT_READ)\r\n\r\n\r\noriginal_time = timeit.timeit(\r\n \"selector.select()\",\r\n number=100000,\r\n globals={\"selector\": original_epoll},\r\n)\r\nnew_time = timeit.timeit(\r\n \"selector.select()\",\r\n number=100000,\r\n globals={\"selector\": new_epoll},\r\n)\r\n\r\nprint(\"original: %s\" % original_time)\r\nprint(\"new: %s\" % new_time)\r\n```\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-106754\n* gh-106864\n* gh-106879\n* gh-106884\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/bdraco","@type":"Person","name":"bdraco"},"datePublished":"2023-07-14T19:48:48.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/106751/cpython/issues/106751"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:edebf4d2-e274-d5a4-8098-81c6d041cbb7 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8B14:E8423:12B01B1:190BB6D:696AD608 |
| html-safe-nonce | 564f7bcf96e6647a42e45c5fcc066f81582dc3bf0d4513e6c9990910b0e153d0 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4QjE0OkU4NDIzOjEyQjAxQjE6MTkwQkI2RDo2OTZBRDYwOCIsInZpc2l0b3JfaWQiOiIxMTg3ODgxMTQwMDA1NTU3NzY4IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | f7f10db535abb5e28038d8636a85be5936b5c6064eed85a5b5a0410049f3b08d |
| hovercard-subject-tag | issue:1805459731 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/106751/issue_layout |
| twitter:image | https://opengraph.githubassets.com/d835696a7c35a695746b466efc84652cb732e86b66b15444a370c3051aedd3cc/python/cpython/issues/106751 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/d835696a7c35a695746b466efc84652cb732e86b66b15444a370c3051aedd3cc/python/cpython/issues/106751 |
| og:image:alt | split out from #106555 (comment) The current EpollSelector can be sped up a bit. This makes quite a difference when there are 100000+ iterations of the event loop per minute (the use case being rec... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | bdraco |
| hostname | github.com |
| expected-hostname | github.com |
| None | c785f4ce187e9e7331257791b36ddee01625bb8e292a9b4fe2c16d4c006abf5d |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | c718a376fcf780eb22089171adb84a543f660bf7 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width