2017-01-24 9 views
8

पर तर्क के रूप में नामांकित किया है। मैं एक छोटा प्रोग्राम लिख रहा हूं जहां मैं एक समारोह को असंकालिक रूप से कॉल करना चाहता हूं ताकि यह कॉलर को अवरुद्ध न करे। ऐसा करने के लिए, मैं पाइथन के multiprocessing मॉड्यूल से Pool का उपयोग कर रहा हूं।पायथन ने apply_async (..) कॉलबैक

समारोह में अतुल्यकालिक रूप से बुलाया जा रहा है मैं एक namedtuple वापस जाने के लिए मेरा कार्यक्रम के बाकी के तर्क के साथ फिट करने के लिए चाहते हैं, लेकिन मैं खोजने रहा है कि एक namedtuple पैदा की प्रक्रिया से पारित करने के लिए एक समर्थित प्रकार होना प्रतीत नहीं होता कॉलबैक के लिए (शायद क्योंकि इसे मसालेदार नहीं किया जा सकता है)। यहां समस्या का न्यूनतम रेपो है।

from multiprocessing import Pool 
from collections import namedtuple 

logEntry = namedtuple("LogEntry", ['logLev', 'msg']) 

def doSomething(x): 
    # Do actual work here 
    logCode = 1 
    statusStr = "Message Here" 
    return logEntry(logLev=logCode, msg=statusStr) 

def callbackFunc(result): 
    print(result.logLev) 
    print(result.msg) 

def userAsyncCall(): 
    pool = Pool() 
    pool.apply_async(doSomething, [1,2], callback=callbackFunc) 

if __name__ == "__main__": 
    userAsyncCall() # Nothing is printed 

    # If this is uncommented, the logLev and status are printed as expected: 
    # y = logEntry(logLev=2, msg="Hello World") 
    # callbackFunc(y) 

किसी को भी अगर वहाँ कॉलबैक करने के लिए async प्रक्रिया से एक namedtuple वापसी मान पारित करने के लिए एक तरीका है पता है? क्या मैं कर रहा हूं इसके लिए एक बेहतर/अधिक पायथन दृष्टिकोण है?

+0

* परिभाषित के रूप में *, अपने नाम पर रखा गया टपल ठीक मसालेदार जा सकता है। देखें [एक नामांकित उदाहरण को सही तरीके से कैसे चुनें] (// stackoverflow.com/q/16377215) –

उत्तर

3

समस्या यह है कि मामले namedtuple() के रिटर्न मान और उसके typename पैरामीटर के लिए अलग है। यही है, नामित tuple की कक्षा परिभाषा और वेरिएबल नाम जो आपने इसे दिया है, के बीच एक मेल नहीं है।

LogEntry = namedtuple("LogEntry", ['logLev', 'msg']) 

और doSomething() तदनुसार में return बयान अद्यतन: आप मैच के लिए दो की जरूरत है।

पूर्ण कोड:

from multiprocessing import Pool 
from collections import namedtuple 

LogEntry = namedtuple("LogEntry", ['logLev', 'msg']) 

def doSomething(x): 
    # Do actual work here 
    logCode = 1 
    statusStr = "Message Here" 
    return LogEntry(logLev=logCode, msg=statusStr) 

def callbackFunc(result): 
    print(result.logLev) 
    print(result.msg) 

def userAsyncCall(): 
    pool = Pool() 
    return pool.apply_async(doSomething, [1], callback=callbackFunc) 

if __name__ == "__main__": 
    c = userAsyncCall() 

    # To see whether there was an exception, you can attempt to get() the AsyncResult object. 
    # print c.get() 

(। वर्ग परिभाषा देखने के लिए, namedtuple() को verbose=True जोड़ें)

3

कारण मुद्रित कुछ भी नहीं है कि apply_async चुपचाप विफल रहा। वैसे, मुझे लगता है कि यह एक बुरा व्यवहार है जो लोगों को उलझन में डाल देता है। त्रुटि को संभालने के लिए आप error_callback पास कर सकते हैं।

def errorCallback(exception): 
    print(exception) 

def userAsyncCall(): 
    pool = Pool() 
    pool.apply_async(doSomething, [1], callback=callbackFunc, error_callback=errorCallback) 
    # You passed wrong arguments. doSomething() takes 1 positional argument. 
    # I replace [1,2] with [1]. 

if __name__ == "__main__": 
    userAsyncCall() 
    import time 
    time.sleep(3) # You need this, otherwise you will never see the output. 

जब आप यहाँ आए थे, उत्पादन

Error sending result: 'LogEntry(logLev=1, msg='Message Here')'. Reason: 'PicklingError("Can't pickle <class '__mp_main__.LogEntry'>: attribute lookup LogEntry on __mp_main__ failed",)' 

PicklingError है! आप सही हैं, namedtuple को उत्पन्न प्रक्रिया से कॉलबैक में पास नहीं किया जा सकता है।

शायद यह एक और अधिक accpetable तरीका नहीं है, लेकिन आप namedtuple बजाय परिणाम के रूप में dict भेज सकते हैं।

जैसा कि डैग होडाहल ने सही किया, नामित किया जा सकता है। निम्नलिखित पंक्ति काम करता है।

LogEntry = namedtuple("LogEntry", ['logLev', 'msg']) 
+0

आपके उत्तर के लिए धन्यवाद। मेरा वर्तमान कामकाज एक 'सूची' है, लेकिन मैं मानता हूं कि एक 'dict' यह संभालने का एक बेहतर तरीका हो सकता है। फिर भी, मैं थोड़ा सा पकड़ने जा रहा हूं और देख सकता हूं कि किसी के पास कोई समाधान है जो 'nametuple' – nbryans

+0

के साथ काम करता है, मैं तर्क दूंगा कि यह उत्तर गलत है। 'पिकलिंग एरर' का कारण यह नहीं है कि नामित टुपल्स को नहीं चुना जा सकता है, लेकिन सही नामित ट्यूपल पिकलिंग के दौरान नहीं मिलता है। –

+0

@ DagHøidahl शुद्धता के लिए धन्यवाद। मैंने 'पिकलिंग एरर' में खोद नहीं लिया और निष्कर्ष निकाला। लेकिन मेरे उत्तर के अन्य भाग सही हैं। :-) – gzc

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