ccxvii / mujs

An embeddable Javascript interpreter in C.
http://mujs.com/
ISC License
812 stars 98 forks source link

multi-thread environment #165

Closed hdcscy closed 2 years ago

hdcscy commented 2 years ago

Now I want to use mujs in a multi-thread environment, and need use a memory snapshot of js_state in the child thread, because the old js_State saves a lot of global functions and variables, I can't create a whole new js_State to execute my js code, this will give an error. I really can't help it now, tried many ways to no avail. Do I have to manually implement a deep copy function myself?

ccxvii commented 2 years ago

Cloning the state is not something we can do easily -- at least not in the general use case.

Userdata objects and RegExps hold pointers to C objects, and the garbage collector will call the destructor when the object is no longer in use by the current state. If there are multiple copies in separate threads, the GC has no way of knowing, and will destroy these objects while still in use by the other state.

You'll need to take good care to make a new obj->u.r.prog instance for RegExps and maybe forbid cloning Userdata objects altogether.

The string interning table is also per-state, so you'll have to re-intern all string values for the cloned state's string table or these strings will become invalid when the old state is destroyed.

hdcscy commented 2 years ago

Cloning the state is not something we can do easily -- at least not in the general use case.

Userdata objects and RegExps hold pointers to C objects, and the garbage collector will call the destructor when the object is no longer in use by the current state. If there are multiple copies in separate threads, the GC has no way of knowing, and will destroy these objects while still in use by the other state.

You'll need to take good care to make a new obj->u.r.prog instance for RegExps and maybe forbid cloning Userdata objects altogether.

The string interning table is also per-state, so you'll have to re-intern all string values for the cloned state's string table or these strings will become invalid when the old state is destroyed.

ok, I will try it out with your suggestion and method, but I'm still worried that something will go wrong. It is because of GC that the multi-threaded environment is very unsafe, and I have not found a simpler general solution. Maybe it shouldn't be in a multithreaded environment, it's true that I'm using it incorrectly. Now I need to use multi-threading to improve performance and execution efficiency, there is no good solution, and I can't build the project without mujs. thank you sir, if you have a good solution, I hope you can enlighten me.

avih commented 2 years ago

improve performance and execution efficiency

Making something multithreaded does not automatically improve efficiency and performance.

You first need to be able to divide your task to sub-tasks which can be executed concurrently.

Assuming this task is JS code which runs in a mujs VM, and you know how to split it into sub-tasks, then your solution is likey not cloning the mujs VM, because mujs is just not written with this goal in mind, and the changes needed are likely to be a big project.

However, what you can do instead of clone is to start a new VM in each thread.

You need to find some way to specify each subtask, e.g. using a JSON string which the "master" VM generates for each new sub-task, and then each new thread starts a new VM and initializes it using its JSON data.

You can already do this right now without any changes in mujs code.

hdcscy commented 2 years ago

improve performance and execution efficiency

Making something multithreaded does not automatically improve efficiency and performance.

You first need to be able to divide your task to sub-tasks which can be executed concurrently.

Assuming this task is JS code which runs in a mujs VM, and you know how to split it into sub-tasks, then your solution is likey not cloning the mujs VM, because mujs is just not written with this goal in mind, and the changes needed are likely to be a big project.

However, what you can do instead of clone is to start a new VM in each thread.

You need to find some way to specify each subtask, e.g. using a JSON string which the "master" VM generates for each new sub-task, and then each new thread starts a new VM and initializes it using its JSON data.

You can already do this right now without any changes in mujs code.

Good idea 👍 Decompose a task into several subtasks and fully decouple each task. I will try my best. Thanks for your detailed answer, this may be the best solution at present.