You have to disable the garbage collection while running the threaded Julia code. Something like this:
def mddf(*args, **kwargs) :
jl.GC.enable(False)
result = jl.cm.mddf(*args, **kwargs) # this is multi-threaded in Julia
jl.GC.enable(True)
return result
Is this a problem even if you aren’t passing any python object to Julia? Does PyCall & Co have the same limitation? This sounds like a severe limitation in JuliaCall and PythonCall
Surprisingly it works without much effort using PyJulia, without disabling the garbage collector. However, I haven’t tested it works well enough yet, without bugs.
Uhm… it worked here, but note that your function allocates a lot, so I cannot run it here without having the GC turned on. Thus, I modified it such that it does not allocate as much. In that case, it worked:
In [1]: from juliacall import Main as jl
In [2]: jl.seval("using FLoops")
In [3]: jl.seval("""
...: function my_func(N)
...: samples=Array{Float64}(undef,N)
...: @floop for i in 1:N
...: samples[i]=sum(i for i in 1:10^4)
...: end
...: return samples
...: end
...: """)
Out[3]: my_func (generic function with 1 method)
In [4]: jl.GC.enable(False)
Out[4]: True
In [5]: jl.my_func(10000)
Out[5]:
10000-element Vector{Float64}:
5.0005e7
...
5.0005e7
In [9]: jl.my_func(10000)
Out[9]:
10000-element Vector{Float64}:
5.0005e7
...
5.0005e7
In [10]: jl.my_func(10000)
Out[10]:
10000-element Vector{Float64}:
5.0005e7
...
5.0005e7
In [11]: jl.my_func(10000)
Out[11]:
10000-element Vector{Float64}:
5.0005e7
...
5.0005e7
In [12]: jl.my_func(10000)
Out[12]:
10000-element Vector{Float64}:
5.0005e7
...
5.0005e7
In [13]: %timeit jl.my_func(10000)
43.4 µs ± 2.72 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [14]: jl.GC.enable(True)
Out[14]: False
In [15]: %timeit jl.my_func(10000)
Segmentation fault (core dumped)
I ran the function several times without GC, and didn’t get the segmentation fault, and then with it I get it. The %timeit macro (from ipython3) runs the function several times.
If I run your original function the section gets Killed because of lack of memory, but that’s another, albeit related, issue.
That is, this limitation does require that the threaded code is minimally allocating, or one can have memory issues given that GC is off on the Julia side.
Anyway, that is a workaround, it may not work in every case, and I’m not a specialist on it.
Does Python replace/override the fault handlers of Julia?
When multi-threaded GC uses read-protected pages to implement safepoints (e.g. to ask other threads to stop doing work). This causes a benign segmentation fault, but it must be handled by the Julia segmentation handler.