2016-10-05 4 views
1

컨텍스트다량의 원인이 교착 상태

나는 multiprocessing.ThreadPool 내부 multiprocessing.Process를 실행해야합니다. 처음에는 이상하게 보입니다 만, C++ 공유 라이브러리를 사용하기 때문에 발생할 수있는 segfault를 처리하는 유일한 방법입니다. segfault가 추가되면 프로세스가 종료되고 process.exitcode를 확인하고 처리 할 수 ​​있습니다. 잠시 후

문제

, 나는이 과정에 참여하려고 교착 추가합니다. 여기

간단한 버전 내 코드입니다 :

import sys, time, multiprocessing 
from multiprocessing.pool import ThreadPool 

def main(): 
    # Launch 8 workers 
    pool = ThreadPool(8) 
    it = pool.imap(run, range(500)) 
    while True: 
     try: 
      it.next() 
     except StopIteration: 
      break 

def run(value): 
    # Each worker launch it own Process 
    process = multiprocessing.Process(target=run_and_might_segfault,  args=(value,)) 
    process.start() 

    while process.is_alive(): 
     sys.stdout.write('.') 
     sys.stdout.flush() 
     time.sleep(0.1) 

    # Will never join after a while, because of a mystery deadlock 
    process.join() 

    # Deals with process.exitcode to log errors 

def run_and_might_segfault(value): 
    # Load a shared library and do stuff (could throw c++ exception, segfault ...) 
    print(value) 

if __name__ == '__main__': 
    main() 

그리고 여기 가능한 출력 : process.is_alive() 몇 반복 후 항상 곁에 사실,

➜ ~ python m.py 
..0 
1 
........8 
.9 
.......10 
......11 
........12 
13 
........14 
........16 
........................................................................................ 

당신이 볼 수 있듯이, 프로세스는 것입니다 절대 가입하지 마라.

만약 내가 CTRL-C 스크립트이 스택 트레이스 수 :

Traceback (most recent call last): 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/multiprocessing/pool.py", line 680, in next 
    item = self._items.popleft() 
IndexError: pop from an empty deque 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "m.py", line 30, in <module> 
    main() 
    File "m.py", line 9, in main 
    it.next() 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/multiprocessing/pool.py", line 684, in next 
    self._cond.wait(timeout) 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/threading.py", line 293, in wait 
    waiter.acquire() 
KeyboardInterrupt 

Error in atexit._run_exitfuncs: 
Traceback (most recent call last): 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/multiprocessing/popen_fork.py", line 29, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
KeyboardInterrupt 

PS 맥 OS에 파이썬 3.5.2를 사용합니다.

모든 종류의 도움을 주셔서 감사합니다.

편집

내가 파이썬 2.7를 사용하여 시도

, 그리고 그것을 잘 작동합니다. 파이썬 3.5 문제 일 수 있습니까?

답변

4

문제는 CPython의 최신 빌드 인 Python 3.7.0a0 (default:4e2cce65e522, Oct 13 2016, 21:55:44)에서도 재생산됩니다.

당신이 gdb를 붙어 프로세스 중 하나에 attach, 당신이 sys.stdout.flush() 전화의 잠금을 획득하려고 것을 알 수있는 경우 :

(gdb) py-list 
263    import traceback 
264    sys.stderr.write('Process %s:\n' % self.name) 
265    traceback.print_exc() 
266   finally: 
267    util.info('process exiting with exitcode %d' % exitcode) 
>268    sys.stdout.flush() 
269    sys.stderr.flush() 
270 
271   return exitcode 

파이썬 수준의 역 추적은 다음과 같습니다

(gdb) py-bt 
Traceback (most recent call first): 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/process.py", line 268, in _bootstrap 
    sys.stdout.flush() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/popen_fork.py", line 74, in _launch 
    code = process_obj._bootstrap() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/popen_fork.py", line 20, in __init__ 
    self._launch(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/context.py", line 277, in _Popen 
    return Popen(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/context.py", line 223, in _Popen 
    return _default_context.get_context().Process._Popen(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/process.py", line 105, in start 
    self._popen = self._Popen(self) 
    File "deadlock.py", line 17, in run 
    process.start() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/pool.py", line 119, in worker 
    result = (True, func(*args, **kwds)) 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 864, in run 
    self._target(*self._args, **self._kwargs) 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 916, in _bootstrap_inner 
    self.run() 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 884, in _bootstrap 
    self._bootstrap_inner() 

(gdb) frame 6 

(gdb) list 
287  return 0; 
288 } 
289 relax_locking = (_Py_Finalizing != NULL); 
290 Py_BEGIN_ALLOW_THREADS 
291 if (!relax_locking) 
292  st = PyThread_acquire_lock(self->lock, 1); 
293 else { 
294  /* When finalizing, we don't want a deadlock to happen with daemon 
295   * threads abruptly shut down while they owned the lock. 
296   * Therefore, only wait for a grace period (1 s.). ... */ 

(gdb) p /x self->lock 
$1 = 0xd25ce0 

(gdb) p /x self->owner 
$2 = 0x7f9bb2128700 

주 : 통역 수준에서

는 같은 보이는 그 잠금 여전히 부모 프로세스의 스레드 중 하나 (LWP 1105)가 소유하고이 특정 자식 프로세스의 관점에서 :

(gdb) info threads 
    Id Target Id   Frame 
* 1 Thread 0x7f9bb5559440 (LWP 1102) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0xe4d340) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 
    2 Thread 0x7f9bb312a700 (LWP 1103) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    3 Thread 0x7f9bb2929700 (LWP 1104) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    4 Thread 0x7f9bb2128700 (LWP 1105) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    5 Thread 0x7f9bb1927700 (LWP 1106) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    6 Thread 0x7f9bb1126700 (LWP 1107) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    7 Thread 0x7f9bb0925700 (LWP 1108) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    8 Thread 0x7f9b9bfff700 (LWP 1109) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    9 Thread 0x7f9b9b7fe700 (LWP 1110) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    10 Thread 0x7f9b9affd700 (LWP 1111) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    11 Thread 0x7f9b9a7fc700 (LWP 1112) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0x7f9b80001ed0) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 
    12 Thread 0x7f9b99ffb700 (LWP 1113) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0x7f9b84001bb0) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 

그래서 참으로 교착 그리고 그것은 사실로 인해 발생하면 그 쓰기 및 플러시를 여러 스레드에서 동시에 수행하는 동안 원래 프로세스에서 서브 프로세스를 생성하는 중 - fork(2) 시스템 호출 의 특성으로 획득 된 잠금을 포함하여 상위 메모리를 자식이 상속 받음 : fork() 잠금을 획득하는 동안 호출이 수행되어야 함 부모 프로세스가 마침내 그것을 풀어 주었을 때도, 아이들은 각각의 메모리 공간을 갖기 때문에 그것을 보지 못합니다. 쓰기가 복사됩니다.

따라서, 당신은 멀티와 멀티 스레딩을 혼합하고 아이들 공정에 사용되는 에있는 경우, 모든 잠금 장치가 제대로 fork() 이전에 출시되어 있는지 확인 할 때 특히주의해야합니다.

그것은 당신이 당신의 조각에서 sys.stdout과의 상호 작용을 제거하면, 제대로 작동하는지, http://bugs.python.org/issue6721

주에 설명 된 것과 매우 유사하다.