Provide a thread safe context api like py-mini-racer
almahdi404 opened this issue ยท 8 comments
In some cases the with
api doesn't work. You need to store the context in an object.
import STPyV8
class Renderer:
def __init__(self):
self.ctx = STPyV8.JSContext()
The py-mini-racer context class(https://github.com/sqreen/PyMiniRacer/blob/f7b9da0d4987ca7d1982af7f24da423f06da9894/py_mini_racer/py_mini_racer.py#L163).
Can you please describe a scenario where this happens? Moreover providing some samples would be great so that I could take a look at them. Thanks!
Thanks for showing interest!
I was trying to use it for SSR in a framework that i built called picomet.
In this(https://github.com/picomet/picomet/blob/main/src/picomet/transformer.py) file you can see how the MiniRacer context class is being used.
Sorry but I still can not understand the issue. If you need to use the JSContext instance multiple times you should really instantiate and use it every time you need it. Be aware that when you use the with statement, the JSContext is created and entered. When you're done the JSContext is exited and destroyed. So the following code
with STPyV8.JSContext() as ctx:
ctx.eval()
does not preserve the created JSContext instance. If you need to do that just use the following code
# Store the JSContext in the object
self.ctx = STPyV8.JSContext()
# Reuse JScontext every time you need (the with statement cleanly and safely enters and exits it)
with self.ctx as ctx:
ctx.eval()
Hope it helps!
Thanks. ๐
# Store the JSContext in the object self.ctx = STPyV8.JSContext() # Reuse JScontext every time you need (the with statement cleanly and safely enters and exits it) with self.ctx as ctx: ctx.eval()
This is what I needed. Now I can persist data and retrieve them later when I need.
But unfortunately it's not thread safe currently. Can it be made thread safe?
Have you already taken a look at https://github.com/cloudflare/stpyv8/blob/master/tests/test_Thread.py? Let me know if that helps.
This doesn't work. I don't know if i am doing something wrong. Or maybe it's not possible.
import threading
import STPyV8
import time
class Global:
count = 0
started = threading.Event()
finished = threading.Semaphore(0)
def sleep(self, ms):
time.sleep(ms / 1000.0)
self.count += 1
g = Global()
def run():
class Transformer:
def __init__(self, *args, **kwargs):
with STPyV8.JSIsolate():
self.ctx = STPyV8.JSContext(g)
def store(self):
with STPyV8.JSIsolate():
with self.ctx as ctx:
ctx.eval(
"""
v = "hello world";
"""
)
def print(self):
with STPyV8.JSIsolate():
with self.ctx as ctx:
print(ctx.eval("v"))
transformer = Transformer()
transformer.store()
transformer.print()
t = threading.Thread(target=run)
t.start()
Seems like you are using different isolates for each operation and that's not correct. Please give this code a try. This should help you figure out how to proceed.
import threading
import STPyV8
class Global:
result = []
def add(self, value):
with STPyV8.JSUnlocker():
self.result.append(value)
class Transformer:
def __init__(self):
self.isolate = STPyV8.JSIsolate()
self.isolate.enter()
self.ctxt = STPyV8.JSContext(Global())
def store(self):
with self.ctxt:
self.ctxt.eval(
"""
add(1234);
"""
)
def print(self):
with self.ctxt:
print(self.ctxt.eval("result"))
def run():
transformer = Transformer()
transformer.store()
transformer.print()
t = threading.Thread(target=run)
with STPyV8.JSLocker():
t.start()
That worked ๐. Thanks for the help and the library.