我在IronPython中定義了一個無副作用(純)的lambda表達式並將其分配給一個C#委託。當從多個線程同時調用委託時,我得到類型爲的異常AccessViolationException,NullReferenceException和FatalEngineExecutionError。爲什麼從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"));
'數百萬迭代'哪個循環?內在,平行還是同時? – leppie