PythonCall.jl
PythonCall.jl copied to clipboard
reducing allocations when checking python coroutines
If I do:
while !Bool(fut.done())
sleep(0.01)
end
where fut
is a future created like:
aio = pyimport("asyncio")
coro = aio.sleep(1)
loop = aio.Runner().get_loop()
aio.run_coroutine_threadsafe(coro, loop)
It allocates linearly the more you sleep.
I tried using a global julia vector [true]
and updating it in place when the future is done, but it doesn't reduce allocations that much, is there a better way?
Is this actually causing issues? The Julia garbage collector only kicks in when you are running out of memory, so it may just be that you haven't run it for long enough for the GC to kick in.
If that were the case only @allocated
would increase, while @allocations
would be somewhat stable? @allocations
still increases linearly the more I sleep, moreover, the number of allocations returned is always the same given the same amount of sleep.
Increasing the sleep time, to reduce the number of iterations also allocates (still linearly) less
Can you give me some code and output that demonstrates the issue please?
using PythonCall
using PythonCall: pynew, pycopy!, pyisnull
using PythonCall.C.CondaPkg
const pyaio = pynew()
const pyuv = pynew()
const pythreads = pynew()
const pyrunner = pynew()
const pyrunner_thread = pynew()
const pyloop = pynew()
start_loop() = begin
pycopy!(pyaio, pyimport("asyncio"))
pycopy!(pyuv, pyimport("uvloop"))
pycopy!(pythreads, pyimport("threading"))
@assert !pyisnull(pyaio)
@assert !pyisnull(pythreads)
@assert pyisnull(pyloop) || !Bool(pyloop.is_running())
@assert pyisnull(pyrunner_thread) || !Bool(pyrunner_thread.is_alive())
pycopy!(pyrunner, pyaio.Runner(; loop_factory=pyuv.new_event_loop))
pycopy!(
pyrunner_thread, pythreads.Thread(; target=pyrunner.run, args=[async_main_func()()])
)
pyrunner_thread.daemon = pybuiltins.True
pyrunner_thread.start()
pycopy!(pyloop, pyrunner.get_loop())
end
function async_main_func()
@pyexec () => """
global asyncio, inf
import asyncio
from math import inf
async def main():
try:
await asyncio.sleep(inf)
finally:
asyncio.get_running_loop().stop()
""" => main
end
function pyschedule(coro::Py)
pyaio.run_coroutine_threadsafe(coro, pyloop)
end
pywait_fut(fut::Py) = begin
while !Bool(fut.done())
sleep(0.01)
end
end
pytask(coro::Py, ::Val{:coro}) = begin
@async let fut = pyschedule(coro)
pywait_fut(fut)
fut.result()
end
end
pytask(f::Py, args...; kwargs...) = pytask(f(args...; kwargs...), Val(:coro))
pyfetch(f::Py, args...; kwargs...) = fetch(pytask(f, args...; kwargs...))
test() = begin
CondaPkg.add_pip("uvloop")
start_loop()
# compile
pyfetch(pyaio.sleep, 0.)
println("@allocated:")
println("Sleeping for 1s")
display(@allocated pyfetch(pyaio.sleep, 1.0))
println("Sleeping for 3s")
display(@allocated pyfetch(pyaio.sleep, 3.0))
println("Sleeping for 9s")
display(@allocated pyfetch(pyaio.sleep, 9.0))
println("\n@allocations")
println("Sleeping for 1s")
display(@allocations pyfetch(pyaio.sleep, 1.0))
println("Sleeping for 3s")
display(@allocations pyfetch(pyaio.sleep, 3.0))
println("Sleeping for 9s")
display(@allocations pyfetch(pyaio.sleep, 9.0))
end
test()
This issue has been marked as stale because it has been open for 30 days with no activity. If the issue is still relevant then please leave a comment, or else it will be closed in 7 days.
This issue has been closed because it has been stale for 7 days. You can re-open it if it is still relevant.