Call LocalReconstruction from tomwer - Cuda contexts
Tomwer can call LocalReconstruction
by several means:
- Using
threading.Thread
orqt.QThread
- Using
multiprocessing.Process
(fork or spawn) - Using
python -m nabu nabu.conf
Using (3) is not elegant as Nabu is supposed to be a python library.
Using (2) + fork gives random cuda context creation/deletion errors.
Using (2) + spawn seems to work fine.
IMO the preferable way would be (1), however it currently does not work because of Cuda context management.
Mixing pycuda and python threads can be tricky, as Cuda contexts are thread-wise (see PyCuda FAQ in "How does PyCUDA handle threading?").
The following approach seem to work. Note that
-
qt.QThread
are used, notthreading.Thread
(not sure they are equivalent - perhaps `qt.QThread are closer to "true" OS threads) to do as in tomwer - A thread call another thread, again to do like in tomwer
- The cuda context must be created in
run()
, not in__init__()
(see for example here). Otherwise the contexts stack is not handled properly.
from silx.gui import qt
from nabu.resources.processconfig import ProcessConfig
from nabu.app.fullfield_cuda import CudaFullFieldPipeline
# This thread creates a new FullFieldPipeline object each time
class InnerThread2(qt.QThread):
def __init__(self, fname, subregion, **kwargs):
super().__init__(**kwargs)
self.proc = ProcessConfig(fname)
self.subregion = subregion
def run(self):
print("In Inner QThread v2")
self.pipeline = CudaFullFieldPipeline(
self.proc, self.subregion, cuda_options={"cleanup_at_exit": False}
)
self.pipeline.process_chunk()
print("End Inner QThread v2")
self.pipeline.ctx.pop()
del self.pipeline.ctx
# Thread calling InnerThread1
class OuterThread(qt.QThread):
def __init__(self, fname, **kwargs):
super().__init__(**kwargs)
self.fname = fname
def run(self):
fname = self.fname
print("In Outer QThread")
I = InnerThread2(fname, (100, 110))
I.start()
I.wait()
print("End Outer Qthread")
if __name__ == "__main__":
fname = "nabu.conf"
T = OuterThread(fname)
T.start()
T.wait()