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