2011-11-26 66 views
28

我在IronPython中定義了一個無副作用(純)的lambda表達式並將其分配給一個C#委託。當從多個線程同時調用委託時,我得到類型爲的異常AccessViolationExceptionNullReferenceExceptionFatalEngineExecutionError爲什麼從C#調用Python lambda表達式不是線程安全的?

錯誤的發生是非確定性的,它大多需要幾百萬次迭代纔會激發它,這對我來說就是「競爭條件」。我如何避免它?

只有在使用x64(x86不會崩潰)和調試器外運行進程時纔會引發異常。測試系統是Windows 7,.NET Framework 4.0和IronPython 2.7.1上的Core I7(8個線程)。

這裏是最少的代碼產生錯誤:

var engine = Python.CreateEngine(); 

double a = 1.0; 
double b = 2.0; 

while (true) 
{ 
    Func<double, double, double> calculate = engine.Execute("lambda a,b : a+b"); 

    System.Threading.Tasks.Parallel.For(0, 1000, _ => 
    { 
     for (int i = 0; i < 1000; i++) { calculate(a,b); } 
    }); 

    Console.Write("."); 
} 

錯誤消息:

FatalExecutionEngineError was detected

Message: The runtime has encountered a fatal error. The address of the error was at 0xf807829e, on thread 0x3da0. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

更新:即使發動機被聲明爲線程局部變量,它崩潰了一段時間後:

var calculate = new ThreadLocal<Func<double, double, double>>(() => Python.CreateEngine().Execute("lambda a,b : a+b")); 
+1

'數百萬迭代'哪個循環?內在,平行還是同時? – leppie

回答

4

這可能是由於ScriptEngine中的競態條件造成的。請注意,ScriptEngine.Execute返回一個對PythonFunction的引用,而不是Func(這是由於C#的動態行爲,你可以把結果當作Func來處理)。我不是IronPython的專家,但查看PythonFunction的來源,任何跡象表明它是線程安全的。

0

運行類似的代碼(見下文)上IronScheme,不會造成這樣的問題。

我能想到的唯一的事情,是engine.Execute("lambda a,b : a+b")創建一個解釋函數,而不是一個編譯的結合可能的線程不安全的翻譯和kaboom

double a = 1.0; 
double b = 2.0; 

while (true) 
{ 
    var calculate = "(lambda (a b) (+ a b))".Eval<Callable>(); 

    System.Threading.Tasks.Parallel.For(0, 1000, _ => 
    { 
    for (int i = 0; i < 1000; i++) { calculate.Call(a, b); } 
    }); 

    Console.Write("."); 
} 
相關問題