2016-07-07 3 views
7

जब विंडोज और लिनक्स (दोनों python2.7 के साथ)क्यों multiprocessing.Process खिड़कियों और वैश्विक वस्तु और समारोह तर्क

'''import_mock.py''' 
to_mock = None 
'''test.py''' 
import import_mock 
from multiprocessing import Process 

class A(object): 
    def __init__(self): 
     self.a = 1 
     self.b = 2 
     self.c = 3 

    def __getstate__(self): 
     print '__getstate__' 
     return { 'a': self.a, 'b': self.b, 
       'c':0 } 

def func(): 
    import_mock.to_mock = 1 
    a = A() 
    return a 

def func1(a): 
    print a.a, a.b, a.c 
    print import_mock.to_mock 


if __name__ == '__main__': 
    a = func() 
    p = Process(target=func1, args=(a,)) 
    p.start() 
    p.join() 

खिड़कियों पर पर चल निम्नलिखित कोड अलग आउटपुट है के लिए लिनक्स पर अलग ढंग से व्यवहार , उत्पादन होता है:

__getstate__ 
1 2 0 
None 

कौन सा मेरी अपेक्षा

पर है लिनक्स, यह है:

1 2 3 
1 

जो वैश्विक वस्तु और पारित तर्कों को क्लोन नहीं करता है।

मेरा सवाल यह है कि वे अलग-अलग व्यवहार क्यों करते हैं? और लिनक्स कोड को विंडोज़ के समान कैसे व्यवहार करना है?

+0

क्योंकि चीजें दो ओएस पर अलग-अलग लागू होती हैं। दस्तावेज़ों का उल्लेख है कि विंडोज़ पर मल्टीप्रोसेसिंग से कई प्रकारों को पिकलेबल करने की आवश्यकता है ताकि बाल प्रक्रियाएं उनका उपयोग कर सकें। निहितार्थ यह है कि अन्य ओएस पर उन्हें होना जरूरी नहीं है। [इस अनुभाग] (https://docs.python.org/2/library/multiprocessing.html#logging) 'मल्टीप्रोसेसिंग' मॉड्यूल के दस्तावेज़ में लॉगिंग पर आपकी विशिष्ट समस्या से मदद मिल सकती है। – martineau

उत्तर

5

@ ब्लैककॉन्ग के उत्तर में जोड़ना: विंडोज़ पर, प्रत्येक प्रक्रिया मूल मॉड्यूल "स्क्रैच से" आयात करती है, जबकि यूनिक्स-वाई सिस्टम पर केवल मुख्य प्रक्रिया पूरे मॉड्यूल को चलाती है, जबकि अन्य सभी प्रक्रियाएं fork() पर मौजूद होती हैं नई प्रक्रियाओं को बनाने के लिए प्रयोग किया जाता है (नहीं, आपfork() को कॉल नहीं करते हैं - multiprocessing आंतरिक इसे जब भी नई प्रक्रिया बनाता है तो कॉल करते हैं)।

विस्तार में, के लिए अपने import_mock:

  • सभी प्लेटफ़ॉर्म पर मुख्य प्रक्रिया कॉल func(), जो सेट import_mock.to_mock 1.

  • यूनिक्स-y प्लेटफार्मों पर, कि क्या सभी नई प्रक्रियाओं है देखें: fork() उसके बाद होता है, इसलिए 1 राज्य सभी नई प्रक्रियाओं का उत्तराधिकारी है।

  • विंडोज़ पर, सभी नई प्रक्रियाएं पूरे मॉड्यूल को "स्क्रैच से" चलाती हैं। इसलिए वे प्रत्येक import_mock का अपना नया, ब्रांड नया संस्करण आयात करते हैं। केवल मुख्य प्रक्रिया func() पर कॉल करती है, इसलिए केवल मुख्य प्रक्रिया to_mock को 1 में बदलती है। अन्य सभी प्रक्रियाओं को ताजा None स्थिति दिखाई देती है।

सभी की उम्मीद है, और वास्तव में आसान है कि दूसरी बार ;-)

क्या गुजर a सूक्ष्म है के साथ हो रहा है समझने के लिए है, क्योंकि यह multiprocessing कार्यान्वयन विवरण के बारे में अधिक निर्भर करता है। कार्यान्वयन ने शुरुआत से सभी प्लेटफार्मों पर तर्क लेने के लिए चुना है, लेकिन ऐसा नहीं हुआ है, और अब पर कुछ प्लेटफॉर्म पर सामान तोड़ने के बिना बदलने में बहुत देर हो चुकी है।

क्योंकि कॉपी-ऑन-राइट fork() अर्थ विज्ञान की

, यह यूनिक्स-y सिस्टम पर Process() तर्क अचार के लिए आवश्यक नहीं था, और इसलिए कार्यान्वयन किया कभी नहीं। हालांकि, fork() के बिना उन्हें विंडोज पर चुनना आवश्यक है - और इसलिए कार्यान्वयन करता है।

पायथन 3.4 से पहले, जो आपको सभी प्लेटफ़ॉर्म पर "विंडोज कार्यान्वयन" (spawn) को मजबूर करने की अनुमति देता है, संभावित क्रॉस-प्लेटफार्म आश्चर्य से बचने के लिए कोई यांत्रिक तरीका नहीं है।

लेकिन व्यवहार में, मुझे शायद ही कभी इस पर परेशान किया गया है। को जानना, उदाहरण के लिए, मल्टीप्रोसेसिंग पिकलिंग पर भारी निर्भर हो सकती है, मैं अचार के साथ चाल चलने के करीब कहीं भी पूरी तरह से स्पष्ट रहती हूं। A() उदाहरण पास करने में "समस्या" होने का एकमात्र कारण यह है कि आप अचार की चाल चल रहे हैं (डिफ़ॉल्ट __getstate__() ओवरराइडिंग के माध्यम से)।

8

लिनक्स (और अन्य यूनिक्स जैसी ओएस) पर, पाइथन के multiprocessing मॉड्यूल fork() का उपयोग करके नई बाल प्रक्रियाएं बनाने के लिए जो माता-पिता की प्रक्रिया की स्मृति स्थिति की प्रतिलिपि को कुशलता से प्राप्त करते हैं। इसका मतलब है कि दुभाषिया को Process के args के रूप में उत्तीर्ण होने वाली वस्तुओं को चुनने की आवश्यकता नहीं है क्योंकि बाल प्रक्रिया पहले से ही उनके सामान्य रूप में उपलब्ध होगी।

विंडोज़ में fork() सिस्टम कॉल नहीं है, इसलिए multiprocessing मॉड्यूल को बच्चे-स्पॉन्गिंग प्रक्रिया को काम करने के लिए थोड़ा और काम करने की आवश्यकता है। fork()-आधारित कार्यान्वयन पहले आया था, और गैर-फोर्किंग विंडोज कार्यान्वयन बाद में आया था।

यह ध्यान देने योग्य है कि पाइथन डेवलपर्स को अक्सर यह महसूस होता था कि यह चाइल्ड प्रक्रियाओं के निर्माण के लिए थोड़ा सा अंतर था, जो आप पाइथन पर चल रहे प्लेटफ़ॉर्म पर आधारित होते हैं। तो पायथन 3.4 में, आपको select the start method that you would prefer to use पर जाने के लिए एक नई प्रणाली जोड़ा गया था। विकल्प "fork", "forkserver" और "spawn" हैं। "fork" विधि यूनिक्स-जैसी प्रणालियों पर डिफ़ॉल्ट बनी हुई है (जहां यह पायथन के पुराने संस्करणों में एकमात्र कार्यान्वयन था)। "spawn" विधि विंडोज पर डिफ़ॉल्ट (और केवल) विकल्प है, लेकिन अब यूनिक्स-जैसी प्रणालियों पर भी इसका उपयोग किया जा सकता है। "forkserver" विधि दोनों के बीच एक संकर का प्रकार है (और केवल कुछ यूनिक्स-जैसी प्रणालियों पर उपलब्ध है)। आप दस्तावेज़ीकरण में विधियों के बीच मतभेदों के बारे में अधिक पढ़ सकते हैं।

संबंधित मुद्दे