1+ import  concurrent .futures 
12import  json 
23import  threading 
4+ from  typing  import  Tuple 
35
46import  _quickjs 
57
@@ -15,15 +17,33 @@ def test():
1517
1618
1719class  Function :
18-  def  __init__ (self , name : str , code : str ) ->  None :
19-  self ._context  =  Context ()
20-  self ._context .eval (code )
21-  self ._f  =  self ._context .get (name )
20+  # There are unit tests demonstrating that we are crashing if different threads are accessing the 
21+  # same runtime, even if it is not at the same time. So we run everything on the same thread in 
22+  # order to prevent this. 
23+  _threadpool  =  concurrent .futures .ThreadPoolExecutor (max_workers = 1 )
24+ 25+  def  __init__ (self , name : str , code : str , * , own_executor = False ) ->  None :
26+  """ 
27+  Arguments: 
28+  name: The name of the function in the provided code that will be executed. 
29+  code: The source code of the function and possibly helper functions, classes, global 
30+  variables etc. 
31+  own_executor: Create an executor specifically for this function. The default is False in 
32+  order to save system resources if a large number of functions are created. 
33+  """ 
34+  if  own_executor :
35+  self ._threadpool  =  concurrent .futures .ThreadPoolExecutor (max_workers = 1 )
2236 self ._lock  =  threading .Lock ()
2337
38+  future  =  self ._threadpool .submit (self ._compile , name , code )
39+  concurrent .futures .wait ([future ])
40+  self ._context , self ._f  =  future .result ()
41+ 2442 def  __call__ (self , * args , run_gc = True ):
2543 with  self ._lock :
26-  return  self ._call (* args , run_gc = run_gc )
44+  future  =  self ._threadpool .submit (self ._call , * args , run_gc = run_gc )
45+  concurrent .futures .wait ([future ])
46+  return  future .result ()
2747
2848 def  set_memory_limit (self , limit ):
2949 with  self ._lock :
@@ -49,6 +69,12 @@ def gc(self):
4969 with  self ._lock :
5070 self ._context .gc ()
5171
72+  def  _compile (self , name : str , code : str ) ->  Tuple [Context , Object ]:
73+  context  =  Context ()
74+  context .eval (code )
75+  f  =  context .get (name )
76+  return  context , f 
77+ 5278 def  _call (self , * args , run_gc = True ):
5379 def  convert_arg (arg ):
5480 if  isinstance (arg , (type (None ), str , bool , float , int )):
0 commit comments