I've devised an ad-hoc non-intrusive solution, just to test things out:
import pyswip, ctypes
class PrologMT(pyswip.Prolog):
"""Multi-threaded (one-to-one) pyswip.Prolog ad-hoc reimpl"""
_swipl = pyswip.core._lib
PL_thread_self = _swipl.PL_thread_self
PL_thread_self.restype = ctypes.c_int
PL_thread_attach_engine = _swipl.PL_thread_attach_engine
PL_thread_attach_engine.argtypes = [ctypes.c_void_p]
PL_thread_attach_engine.restype = ctypes.c_int
@classmethod
def _init_prolog_thread(cls):
pengine_id = cls.PL_thread_self()
if (pengine_id == -1):
pengine_id = cls.PL_thread_attach_engine(None)
print("{INFO} attach pengine to thread: %d" % pengine_id)
if (pengine_id == -1):
raise pyswip.prolog.PrologError("Unable to attach new Prolog engine to the thread")
elif (pengine_id == -2):
print("{WARN} Single-threaded swipl build, beware!")
class _QueryWrapper(pyswip.Prolog._QueryWrapper):
def __call__(self, *args, **kwargs):
PrologMT._init_prolog_thread()
return super().__call__(*args, **kwargs)
PrologMT is a drop-in replacement for pyswip.Prolog in your code. On each query, native thread's local storage is scanned for the prolog engine (PL_thread_self). If there is no pengine associated with the current thread, new one will be created (PL_thread_attach_engine), without any further resource management.
You couldn't use any term_t-related functions of libswipl from the thread with no pengine - that leads to SEGFAULT. By default, the thread which imports pyswip first, will be implicitly associated with the single ("main") pengine, as PL_initialise is called on the pyswip.prolog module top-level.
Multithreading was possible after the suggested solution. However, I receive a NestedQueryError("The last query was not closed") exception whenever multiple threads try to perform the "query" operation. So is there any inherent "Queue" mechanism involved for "query" operations to avoid the above error? If not, kindly suggest some other solution for the same.
With reference to issue #120 (https://github.com/yuce/pyswip/issues/120), The following solution mentioned in issue #3 was implemented for it.
pyswip
doesn't support multithreading at all. IMHO, contemporary API (or at leastpyswip.prolog
module) needs to be redesigned from the scratch, see: http://www.swi-prolog.org/pldoc/man?section=foreignthreadI've devised an ad-hoc non-intrusive solution, just to test things out:
PrologMT
is a drop-in replacement forpyswip.Prolog
in your code. On each query, native thread's local storage is scanned for the prolog engine (PL_thread_self
). If there is no pengine associated with the current thread, new one will be created (PL_thread_attach_engine
), without any further resource management. You couldn't use anyterm_t
-related functions oflibswipl
from the thread with no pengine - that leads to SEGFAULT. By default, the thread which importspyswip
first, will be implicitly associated with the single ("main") pengine, asPL_initialise
is called on thepyswip.prolog
module top-level.Originally posted by @xpinguin in https://github.com/yuce/pyswip/issues/3#issuecomment-355458825
Multithreading was possible after the suggested solution. However, I receive a NestedQueryError("The last query was not closed") exception whenever multiple threads try to perform the "query" operation. So is there any inherent "Queue" mechanism involved for "query" operations to avoid the above error? If not, kindly suggest some other solution for the same.