Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Closed
Description
Feature or enhancement
Proposal:
Consider the following use case:
An asyncio event loop where the majority of the handles being run have a very small run time because they are decoding Bluetooth or Zigbee packets.
In this case_run_once becomes a bit of a bottleneck. In production, themin andmax calls to find the timeout represent a significant portion of the run time. We can increase the number of packets that can be processed per second by switching themin andmax to a simple> and< check.
importheapqimporttimeitfromasyncioimporteventsfromasyncio.base_eventsimport (_MIN_CANCELLED_TIMER_HANDLES_FRACTION,_MIN_SCHEDULED_TIMER_HANDLES,MAXIMUM_SELECT_TIMEOUT,BaseEventLoop,_format_handle,logger,)fromtimeimportmonotonicclassFakeSelector:defselect(self,timeout):"""Wait for I/O events."""fake_selector=FakeSelector()original_loop=BaseEventLoop()original_loop._selector=fake_selectororiginal_loop._process_events=lambdaevents:Nonetimer=events.TimerHandle(monotonic()+100000,lambda:None, ("any",),original_loop,None)timer._scheduled=Trueheapq.heappush(original_loop._scheduled,timer)classOptimizedBaseEventLoop(BaseEventLoop):def_run_once(self):"""Run one full iteration of the event loop. This calls all currently ready callbacks, polls for I/O, schedules the resulting callbacks, and finally schedules 'call_later' callbacks. """sched_count=len(self._scheduled)if (sched_count>_MIN_SCHEDULED_TIMER_HANDLESandself._timer_cancelled_count/sched_count>_MIN_CANCELLED_TIMER_HANDLES_FRACTION ):# Remove delayed calls that were cancelled if their number# is too highnew_scheduled= []forhandleinself._scheduled:ifhandle._cancelled:handle._scheduled=Falseelse:new_scheduled.append(handle)heapq.heapify(new_scheduled)self._scheduled=new_scheduledself._timer_cancelled_count=0else:# Remove delayed calls that were cancelled from head of queue.whileself._scheduledandself._scheduled[0]._cancelled:self._timer_cancelled_count-=1handle=heapq.heappop(self._scheduled)handle._scheduled=Falsetimeout=Noneifself._readyorself._stopping:timeout=0elifself._scheduled:# Compute the desired timeout.timeout=self._scheduled[0]._when-self.time()iftimeout>MAXIMUM_SELECT_TIMEOUT:timeout=MAXIMUM_SELECT_TIMEOUTeliftimeout<0:timeout=0event_list=self._selector.select(timeout)self._process_events(event_list)# Needed to break cycles when an exception occurs.event_list=None# Handle 'later' callbacks that are ready.end_time=self.time()+self._clock_resolutionwhileself._scheduled:handle=self._scheduled[0]ifhandle._when>=end_time:breakhandle=heapq.heappop(self._scheduled)handle._scheduled=Falseself._ready.append(handle)# This is the only place where callbacks are actually *called*.# All other places just add them to ready.# Note: We run all currently scheduled callbacks, but not any# callbacks scheduled by callbacks run this time around --# they will be run the next time (after another I/O poll).# Use an idiom that is thread-safe without using locks.ntodo=len(self._ready)foriinrange(ntodo):handle=self._ready.popleft()ifhandle._cancelled:continueifself._debug:try:self._current_handle=handlet0=self.time()handle._run()dt=self.time()-t0ifdt>=self.slow_callback_duration:logger.warning("Executing %s took %.3f seconds",_format_handle(handle),dt )finally:self._current_handle=Noneelse:handle._run()handle=None# Needed to break cycles when an exception occurs.new_loop=OptimizedBaseEventLoop()new_loop._selector=fake_selectornew_loop._process_events=lambdaevents:Nonetimer=events.TimerHandle(monotonic()+100000,lambda:None, ("any",),new_loop,None)timer._scheduled=Trueheapq.heappush(new_loop._scheduled,timer)new_time=timeit.timeit("loop._run_once()",number=1000000,globals={"loop":new_loop},)print("new: %s"%new_time)original_time=timeit.timeit("loop._run_once()",number=1000000,globals={"loop":original_loop},)print("original: %s"%original_time)
new: 0.36033158400096original: 0.4667800000170246Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Linked PRs
Metadata
Metadata
Assignees
Projects
Status
Done