Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder4.news.weretis.net!feeds.phibee-telecom.net!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'that?': 0.05; 'debug': 0.07; 'finally:': 0.07; 'important,': 0.07; 'skip:" 60': 0.07; 'string': 0.09; 'callback': 0.09; 'exception,': 0.09; 'get(self,': 0.09; 'happen,': 0.09; 'obj': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'release,': 0.09; 'subject:module': 0.09; 'try:': 0.09; 'python': 0.11; 'def': 0.12; 'jan': 0.12; '2.7': 0.14; 'attributes.': 0.16; 'called,': 0.16; 'concatenate': 0.16; 'did,': 0.16; 'get,': 0.16; 'iterable,': 0.16; 'none.': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'returned,': 0.16; 'set,': 0.16; 'subject:Problem': 0.16; 'targets': 0.16; 'typeerror:': 0.16; 'wait.': 0.16; 'wing': 0.16; 'fix': 0.17; 'wrote:': 0.18; '(not': 0.18; 'stack': 0.19; 'starts': 0.20; 'seems': 0.21; '(the': 0.22; '>>>': 0.22; 'import': 0.22; 'header:User-Agent:1': 0.23; 'error': 0.23; 'string,': 0.24; '(or': 0.24; 'sort': 0.25; 'equivalent': 0.26; 'nearly': 0.26; 'task': 0.26; 'skip:_ 20': 0.27; 'gets': 0.27; 'header:X-Complaints-To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'tried': 0.27; 'function': 0.29; 'am,': 0.29; 'raise': 0.29; 'relative': 0.30; 'returned': 0.30; 'skip:@ 10': 0.30; 'strongly': 0.30; "i'm": 0.30; '(which': 0.31; 'gives': 0.31; 'program,': 0.31; 'code': 0.31; 'lines': 0.31; "skip:' 10": 0.31; '"",': 0.31; 'object.': 0.31; 'ray': 0.31; 'time:': 0.31; 'file': 0.32; 'class': 0.32; 'figure': 0.32; 'skip:m 30': 0.32; 'up.': 0.33; 'running': 0.33; '(most': 0.33; 'mac': 0.33; 'skip:_ 10': 0.34; 'maybe': 0.34; "i'd": 0.34; 'could': 0.34; 'problem': 0.35; "can't": 0.35; 'something': 0.35; 'convert': 0.35; 'objects': 0.35; 'but': 0.35; 'there': 0.35; 'version': 0.36; 'really': 0.36; 'false': 0.36; 'functions.': 0.36; 'library.': 0.36; 'module.': 0.36; 'sequence': 0.36; 'doing': 0.36; 'method': 0.36; 'wrong': 0.37; 'turn': 0.37; 'two': 0.37; 'being': 0.38; 'expected': 0.38; 'remote': 0.38; 'ends': 0.38; 'skip:. 20': 0.38; 'skip:m 40': 0.38; 'whatever': 0.38; 'to:addr:python-list': 0.38; 'track': 0.38; 'recent': 0.39; 'skip:_ 30': 0.39; 'does': 0.39; 'moving': 0.39; 'to:addr:python.org': 0.39; 'skip:p 20': 0.39; 'received:org': 0.40; 'called': 0.40; 'expression': 0.60; 'is.': 0.60; 'tell': 0.60; 'skip:t 30': 0.61; 'received:173': 0.61; 'first': 0.61; 'save': 0.62; 'confirm': 0.64; 'map': 0.64; 'more': 0.64; 'different': 0.65; '20,': 0.68; 'below.': 0.71; 'cut': 0.74; 'william': 0.81; 'received:fios.verizon.net': 0.84; 'subject:skip:M 10': 0.84; 'suspicion': 0.84; 'terrible': 0.84; 'top.': 0.84; 'exposing': 0.91; 'hands': 0.96 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: Problem in Multiprocessing module Date: Fri, 11 Oct 2013 18:58:44 -0400 References: <852C0701-6B21-4ACA-98FF-CF2261D92C2D@mac.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: pool-173-75-251-66.phlapa.fios.verizon.net User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.0 In-Reply-To: <852C0701-6B21-4ACA-98FF-CF2261D92C2D@mac.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 152 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1381532341 news.xs4all.nl 15891 [2001:888:2000:d::a6]:56275 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:56717 On 10/11/2013 10:53 AM, William Ray Wing wrote: > I'm running into a problem in the multiprocessing module. > > My code is running four parallel processes which are doing network access completely independently of each other (gathering data from different remote sources). On rare circumstances, the code blows up when one of my processes has do start doing some error recovery. I strongly suspect it is because there is a time-out that isn't being caught in the multiprocessing lib, and that in turn is exposing the TypeError. Note that the error is "cannot concatenate 'str' and 'NoneType' objects and it is occurring way down in the multiprocessing library. > > I'd really appreciate it if someone more knowledgeable about multiprocessing could confirm (or refute) my suspicion and then tell me how to fix things up. > > I'm running python 2.7.5 on a Mac OS-X 10.8.5 The version is important, see below. > The traceback I get is: After moving the last line to the top. Better to cut and paste as is. > TypeError: cannot concatenate 'str' and 'NoneType' objects To understand an exception, you must know what sort of expression could cause it. In 2.7, this arises from something like >>> 'a'+None Traceback (most recent call last): File "", line 1, in 'a'+None TypeError: cannot concatenate 'str' and 'NoneType' objects In 3.x, the same expression generates TypeError: Can't convert 'NoneType' object to str implicitly The equivalent join expression gives a different message in 2.7 (and nearly the same in 3.3): >>> ''.join(('a', None)) Traceback (most recent call last): File "", line 1, in ''.join(('a', None)) TypeError: sequence item 1: expected string, NoneType found > File "/Users/wrw/Dev/Python/Connection_Monitor/Version3.0/CM_Harness.py", line 20, in > my_pool = pool.map(monitor, targets) # and hands off to four targets > File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 250, in map > return self.map_async(func, iterable, chunksize).get() > File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 554, in get > raise self._value > > To save you-all some time: > > The "get" function at line 554 in pool.py (which is in the multiprocessing lib) is: class ApplyResult(object): > def get(self, timeout=None): > self.wait(timeout) This must set self._ready, self._success, and self._value > if not self._ready: > raise TimeoutError This did not happen, so self._ready must be True > if self._success: > return self._value This did not happen, so self._success must be False > else: > raise self._value This did, and self._value is the TypeError reported. Let us look into self.wait and see if we can find where there is a string1 + string2 expression and then figure out how string2 might be None. class ApplyResult(object): def __init__(self, cache, callback): self._cond = threading.Condition(threading.Lock()) ... threading.Condition is a (useless) function that returns a class _Condition object. def wait(self, timeout=None): self._cond.acquire() try: if not self._ready: self._cond.wait(timeout) finally: self._cond.release() so it seems that we need to look at the _Condition methods acquire, release, and wait. (The first two are lock methods self.acquire = lock.acquire self.release = lock.release ). However, this seems wrong because self._cond has no reference to self and hence cannot set self attributes. The problem must be in some callback that is called while waiting. Async is terrible to debug because the call stack in the traceback ends with wait and does not tell us what function was called during the wait. After the .get method is ._set, which starts def _set(self, i, obj): self._success, self._value = obj # and goes on to set This is the only place where self._value is set, so it must have been called during the wait. It is only used in Pool._handle_results where the relevant lines are @staticmethod def _handle_results(outqueue, get, cache): ... task = get() ... job, i, obj = task ... cache[job]._set(i, obj) We need to find out what get is. _handle_results is only used in Pool.__init__: self._result_handler = threading.Thread( target=Pool._handle_results, args=(self._outqueue, self._quick_get, self._cache) ) so when _handle_results is called, get = self._quick_get, and what is that? .__init__ starts with self._setup_queues(self) and that has from .queues import SimpleQueue # relative import self._outqueue = SimpleQueue() self._quick_get = self._outqueue._reader.recv SimpleQueue._reader is the first member of the pair returned by multiprocessing.Pipe(duplex=False), which calls multiprocessing.connection.Pipe(duplex). For duplex=False, that in turn returns two _multiprocessing.Connections (not Windows) or PipeConnections (Windows). So it seems that get = _quick_get = _multiprocessing(Pipe)Connection.recv. I tried looking at the C code for conn_recv_string() in Modules/_multiprocessing/pipe_connection and conn_recv_bytes in .../socket_connection, but did not get very far. I do not see how a triple could be returned, nor any string concatenation. If I am on the right track, the concatenation would have to be deeper in one of the called functions. But maybe I am on the wrong track and the problem is in your monitor program, or whatever part gets called as part of the callback. -- Terry Jan Reedy