This project is read-only.

Multiple contexts and threads

Sep 13, 2010 at 5:53 AM

First off, hats off to you guys for offering your hard work as open source. 

Secondly, this is a great concept and I think this particular DLR will see vast numbers of use cases in the coming months/years.

Now, here are some anecdotal observations.  If I have a large javascript object model and script space, it appears that is possible for me to contx.Run(largescript) and then immediately attempt to access some of the javascript variables and methods that the script loaded. However, at times, I can choke the contx.Run by running a referencing script too quickly. It seems as if the context needs time to fully parse and execute the large javascript code file before it's available for use, would this in fact be true? Or am I just experiencing some other anomaly?

I'm using worker threads and queues to synchronize access to the javascript context so that the context can process the new "Run(xyz)"s completely before I send the next command through. I'm receiving externally sourced events that I must pinch off of a COM stack in order to make sure the processing of these events does not block the event source. I queue these received events and use worker threads to process them through the contx.Run. I'm getting some odd results which appears that the context can't completely run the script segments (JSON blocks and javascript method calls). I trap the contx.Run fails but no details are available. The script runs just fine generally, if events are slow.

Lastly, I want to run a suite of javascript context's. I dedicate a WinForm per context and run timers into the context to test throughput. If I start more than one context with heavy event processing I'll actually get a 

System.AccessViolationException was unhandled  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.  Source=Noesis.Javascript  StackTrace:       at v8.Script.Run(Script* , Local<v8::Value>* )       at Noesis.Javascript.JavascriptContext.Run(String iSourceCode)       at MbtCS.FrmScripting.HandleScriptCommandQueuedEvent(Object state) in FrmScripting.cs:line 637       at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)       at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()       at System.Threading.ThreadPoolWorkQueue.Dispatch()       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()  InnerException: 

Any clues as to why or what I can do to avoid this?

If I can get beyond these issues, which are blockers, I'll be in love, in absolute infatuation.

Thanks,

AM

 

Sep 14, 2010 at 3:35 PM
Edited Sep 14, 2010 at 3:35 PM

Hi there,

The problems you're are facing are probably related to the use of V8 in a multi-threaded context. Unfortunately, V8 was designed by the Google team in a way that the API can only be accessed by one thread a time. In fact Google Chrome is designed as a multi-process application and uses a single context per process.

One way to solve this is to create child processes managed by a process pool and establish connectivity between processes using WCF. This isn't as elegant but it may be a good alternative.

Cheers

The Noesis Team

Sep 14, 2010 at 4:26 PM

Noesis,

Thanks for the reply, acknowledged and understood. The DLRs in Ruby and Python are capable of multiple thread access do you know? Not that I could deal with using such clunky and clumsily formatted languages. Are there other javascript engines  which would allow such seemingly natural execution organization?

Using WCF I'll essentially end up building a datagateway which adds considerable technical hurdles. But thanks for the suggestion. I may work up a sample to see how difficult the management overhead might be.

AM

Sep 14, 2010 at 6:02 PM
Edited Sep 15, 2010 at 7:59 PM

These multi-threading issues were discovered at the last moments of the Javascript .NET proof of concept development. While V8 offers good performance, this limitation induces important design constraints. We were able to recover from this constraint by using a multi-process architecture.

You can explore using Spidermonkey which would have been a great alternative to V8 as it offers a thread-safe implementation.

Sep 16, 2010 at 10:25 PM
Edited Sep 16, 2010 at 11:23 PM

"You can explore using Spidermonkey which would have been a great alternative to V8 as it offers a thread-safe implementation."

Codeplex has a spidermonkeydotnet repository and there's been a 0.30 Alpha released just this past July.

This might be the ticket for anyone who needs the thread safety.   Also, someone could take this work and bind it to the TraceMonkey spinoff of SpiderMonkey in order to get some speed improvements.   It looks like the two (SpiderMonkey/TraceMonkey) are compatible from an embedded API standpoint.

Oops...just so you know though...

There's a commercial license clause though if you're using it for other than R&D purposes:

"...This is a license for research and development use only, and does not include a license for commercial use."

Two more ideas:

1. There's an ironjs project in the works over at github, but it's a one-man project and not complete yet.  He's going to use the DLR.

2. Is the new beta IE9 Javascript engine thread safe and can it be embedded into C#?  If yes, then I'm guessing it would be through an ActiveX interface (I can't find the docs at Microsoft yet though).

jint.codeplex.com looks nice but it's got to be dog slow.  They didn't take the DLR approach.

 

Sep 18, 2010 at 11:17 PM
Edited Sep 18, 2010 at 11:18 PM

I gave Jint a go but found that its impl was, to what I could tell, broken. And its mode of execution not at all what I had expected nor can use (I think).

Spidermonkeydotnet looks halfbaked and strangely complex.

IronJS compiles but damn if I can figure out the F# nonsense language it's using to run the tests. And then translate that into something simple like engine.Run(script);

Nope, It looks like JavaScriptDotNet is the winner here. Now, if I can only get past my throughput tests...

But, your post was well received and I thank you for the time you took to offer alternatives.

Sep 22, 2010 at 2:45 AM

I was also caught out by the thread safety issues in v8.  v8 provides a global lock object (v8::Locker in v8.h) to ensure threads don't try to use v8 at the same time, which perhaps javascriptdotnet should apply.  Also, when operating in multiple threads you must manually the stack limit.  If not then you will get a stack overflow if any thread is allocated a stack lower with a lower starting address than the stack used by the first thread that uses v8.  I have this in my customised JavascriptContext::JavascriptContext:

static DWORD curThreadId;
...
    // v8 Needs to have its stack limit set separately in each thread.
    DWORD dw = GetCurrentThreadId();
    if (dw != curThreadId) {
        v8::ResourceConstraints rc;
        int limit = (int)&rc - 500000;
        rc.set_stack_limit((uint32_t *)(limit));
        v8::SetResourceConstraints(&rc);
        curThreadId = dw;
    }

Figuring this out was really hard because the v8 error messages do not go to the console (as the should) and the problem disappears whenever you turn on the native-mode debugger, probably because stacks are arranged differently.