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