Skip to content

Commit 1912270

Browse files
generatedunixname1395027625275998meta-codesync[bot]
authored andcommitted
Add MRU executor cache to folly/python get_running_executor_drive
Reviewed By: MatzeB Differential Revision: D116524117 fbshipit-source-id: 608749f4a9fa96bc08ad0aee1a6cea80f5dc0e7e
1 parent 8d115d3 commit 1912270

1 file changed

Lines changed: 38 additions & 11 deletions

File tree

third-party/folly/src/folly/python/executor.pyx

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,25 @@ from libcpp.memory cimport make_unique, unique_ptr
2020
from cython.operator cimport dereference as deref
2121
from weakref import WeakKeyDictionary
2222
from cpython.ref cimport PyObject
23+
from cpython.weakref cimport PyWeakref_NewRef, PyWeakref_GetObject
2324

2425
# asyncio Loops to AsyncioExecutor
2526
loop_to_q = WeakKeyDictionary()
2627
_RaiseKeyError = object()
2728

29+
# weak reference to the last seen event loop
30+
_last_loop = None
31+
# AsyncioExecutor for the last seen event loop
32+
_last_executor = None
33+
34+
35+
# cleanup callback that clears _last_loop and _last_executor when the loop
36+
# referenced by _last_loop is collected
37+
def _clean_last_executor(_wr):
38+
global _last_loop, _last_executor
39+
_last_loop = None
40+
_last_executor = None
41+
2842

2943
cdef class AsyncioExecutor:
3044
def __cinit__(self):
@@ -112,28 +126,41 @@ cdef cAsyncioExecutor* get_running_executor(bint running) noexcept:
112126

113127
cdef cAsyncioExecutor* get_running_executor_drive(
114128
bint running, bint driveBeforeDealloc) noexcept:
129+
global _last_loop, _last_executor
115130
try:
116131
if running:
117132
loop = asyncio.get_running_loop()
118133
else:
119134
loop = asyncio.get_event_loop()
120135
except RuntimeError:
121136
return NULL
122-
try:
123-
executor = <AsyncioExecutor>(loop_to_q[loop])
124-
except KeyError:
125-
if sys.platform == "win32":
126-
executor = ProactorExecutor(loop._proactor._iocp)
127-
queue = IocpQueue(executor)
128-
queue.swap(loop)
129-
else:
130-
executor = NotificationQueueAsyncioExecutor(driveBeforeDealloc)
131-
loop.add_reader(executor.fileno(), executor.drive)
132-
loop_to_q[loop] = executor
137+
cdef AsyncioExecutor executor = None
138+
if _last_loop is not None and <PyObject*>loop is PyWeakref_GetObject(_last_loop):
139+
executor = _last_executor
140+
if executor is None:
141+
try:
142+
executor = <AsyncioExecutor>(loop_to_q[loop])
143+
except KeyError:
144+
if sys.platform == "win32":
145+
proactor = ProactorExecutor(loop._proactor._iocp)
146+
queue = IocpQueue(proactor)
147+
queue.swap(loop)
148+
executor = proactor
149+
else:
150+
nq = NotificationQueueAsyncioExecutor(driveBeforeDealloc)
151+
loop.add_reader(nq.fileno(), nq.drive)
152+
executor = nq
153+
loop_to_q[loop] = executor
154+
_last_loop = PyWeakref_NewRef(loop, _clean_last_executor)
155+
_last_executor = executor
133156
return executor._executor
134157

135158

136159
cdef int set_executor_for_loop(object loop, cAsyncioExecutor* c_executor) noexcept:
160+
global _last_loop, _last_executor
161+
# drop the fast-path cache to avoid returning a stale executor
162+
_last_loop = None
163+
_last_executor = None
137164
if c_executor == NULL:
138165
del loop_to_q[loop]
139166
return 0

0 commit comments

Comments
 (0)