2011-11-26 9 views
28

मैं आयरनपीथन में साइड-इफेक्ट-फ्री (शुद्ध) लैम्ब्डा अभिव्यक्ति परिभाषित करता हूं और इसे सी # प्रतिनिधि को सौंपता हूं। जब एक से अधिक थ्रेड से एक साथ प्रतिनिधि लागू मैं प्रकार AccessViolationException, NullReferenceException और FatalEngineExecutionError के अपवाद मिलता है।सी # थ्रेड-सुरक्षित नहीं होने पर पाइथन लैम्बडा अभिव्यक्ति क्यों कॉल कर रहा है?

त्रुटि का उद्भव गैर-निर्धारक है और इसे उत्तेजित करने के लिए इसे कई मिलियन पुनरावृत्तियों का सामना करना पड़ता है, जो मुझे "दौड़ की स्थिति" कहता है। मैं इससे कैसे बच सकता हूं?

अपवाद केवल x64 (x86 क्रैश नहीं होता है) और डीबगर के बाहर प्रक्रिया चलाने पर उठाए जाते हैं। परीक्षण प्रणाली विंडोज 7, .NET Framework 4.0 और IronPython 2.7.1 पर कोर 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

उत्तर

1

क्या आपने 32 बिट डेटा प्रकार (फ्लोट) के साथ 64 बिट डेटा प्रकार (डबल) को बदलने की कोशिश की है? मुझे पता है कि "A simple read or write on a field of 32 bits or less is always atomic" जबकि 64 बिट फ़ील्ड प्रोसेसर और कोड के आधार पर समस्याएं हो सकती है। ऐसा लगता है कि यह एक लंबा शॉट है लेकिन यह एक कोशिश के लायक है।

+0

फ्लोट करने के लिए डबल बदलना मदद नहीं करता है। – Rauhotz

4

यह स्क्रिप्टइंजिन के भीतर दौड़ की स्थिति के कारण होने की संभावना है। ध्यान दें कि ScriptEngine.Execute एक Func के बजाय एक पायथन फ़ंक्शन का संदर्भ देता है (यह सी # के गतिशील व्यवहार के कारण है, कि आप परिणाम को Func के रूप में देख सकते हैं। मैं आयरनपीथन पर कोई विशेषज्ञ नहीं हूं लेकिन पाइथन फंक्शन के स्रोत को देख रहा हूं, वहां है कोई संकेत नहीं है जो भी है कि यह threadsafe है।

0

समान कोड चल रहा है (नीचे देखें) IronScheme पर, ऐसी कोई मुद्दों बन गया है।

केवल एक चीज मैं के बारे में सोच सकते हैं, कि engine.Execute("lambda a,b : a+b") एक संकलित करने के बजाए एक व्याख्या समारोह बनाता है एक। संभावित रूप से थ्रेड असुरक्षित दुभाषिया, और कबाब के साथ संयोजन करें।

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("."); 
} 
संबंधित मुद्दे