3

부모 프로세스가 분기 될 때 전역 개체가 공유 또는 복사되는지 평가하려면이 코드를 script (끝에있는 코드 참조)이라고 사용했습니다.다중 처리 : 목록이 복사되는 동안 왜 numpy 배열이 하위 프로세스와 공유됩니까?

간단히 말해서 스크립트는 전체 data 개체를 만들고 하위 프로세스는 data 이상의 반복을 처리합니다. 스크립트는 또한 개체가 자식 프로세스에 복사되었는지 여부를 평가하기 위해 메모리 사용을 모니터링합니다.

  1. data = np.ones((N,N)) :

    여기 결과이다. 하위 프로세스의 작업 : data.sum(). 결과 : data공유 (복사 안 함)

  2. data = list(range(pow(10, 8)))입니다. 하위 프로세스의 작업 : sum(data). 결과 : data입니다.
  3. data = list(range(pow(10, 8))). 하위 프로세스의 작업 : for x in data: pass. 결과 : data입니다.

결과 1) copy-on-write 때문에 예상됩니다. 나는 결과 2)와 3)에 의아해한다. data은 왜 복사 되었습니까?


스크립트

source

import multiprocessing as mp 
import numpy as np 
import logging 
import os 

logger = mp.log_to_stderr(logging.WARNING) 

def free_memory(): 
    total = 0 
    with open('/proc/meminfo', 'r') as f: 
     for line in f: 
      line = line.strip() 
      if any(line.startswith(field) for field in ('MemFree', 'Buffers', 'Cached')): 
       field, amount, unit = line.split() 
       amount = int(amount) 
       if unit != 'kB': 
        raise ValueError(
         'Unknown unit {u!r} in /proc/meminfo'.format(u = unit)) 
       total += amount 
    return total 

def worker(i): 
    x = data.sum() # Exercise access to data 
    logger.warn('Free memory: {m}'.format(m = free_memory())) 

def main(): 
    procs = [mp.Process(target = worker, args = (i,)) for i in range(4)] 
    for proc in procs: 
     proc.start() 
    for proc in procs: 
     proc.join() 

logger.warn('Initial free: {m}'.format(m = free_memory())) 
N = 15000 
data = np.ones((N,N)) 
logger.warn('After allocating data: {m}'.format(m = free_memory())) 

if __name__ == '__main__': 
    main() 

자세한 결과

경기 1 개 출력

012,384,365,417,471,

실행이 출력

[WARNING/MainProcess] Initial free: 25.1 GB [WARNING/MainProcess] After allocating data: 21.9 GB [WARNING/Process-2] Free memory: 12.6 GB [WARNING/Process-4] Free memory: 12.7 GB [WARNING/Process-1] Free memory: 16.3 GB [WARNING/Process-3] Free memory: 17.1 GB

실행 3 출력

[WARNING/MainProcess] Initial free: 25.1 GB [WARNING/MainProcess] After allocating data: 21.9 GB [WARNING/Process-2] Free memory: 12.6 GB [WARNING/Process-4] Free memory: 13.1 GB [WARNING/Process-1] Free memory: 14.6 GB [WARNING/Process-3] Free memory: 19.3 GB

답변

3

그들은 모두 기록 중 복사입니다. 당신이 놓치고있는 것은 당신이 할 때 x가 차례로 각 개체에 바인딩으로, 예를 들어, data에 포함 된 모든 객체에

for x in data: 
    pass 

참조 카운트가 일시적으로, 1, 한 번에 하나 씩 증가한다는 것입니다. int 개체의 경우 CPython의 refcount는 기본 개체 레이아웃의 일부이므로 개체가 복사됩니다. 으로 변경되었으므로 refcount가 변경됩니다.

numpy.ones 사례와 더 비슷한 것을 만들려면 다음을 시도해보십시오.,

data = [1] * 10**8 

그런 다음 목록이 많은 (10**8) 번 참조 하나의 객체 만이, 그래서 (같은 개체의 참조 카운트가 증가하고 많은 시간을 감소됩니다) 복사 거의있다.

+0

좋아, 그래서 나는 복사를 트리거하지 않고 간단한 조회를 반복하거나 할 수 없다. 쓸모없는 부분에 copy-on-write를 만들지 않습니까? –

+2

COW (copy-on-write)는 Python이 그 기능을 지원하는 플랫폼에서'fork()'에서 상속받는 OS 개념이다. COW는 Python의 다중 처리 (mp)를 염두에두고 설계된 것이 아니며 Python의 mp는 COW를 염두에두고 설계되지 않았습니다 ;-) COW는 플랫폼에 따라 다르며 응용 프로그램에 따라 유용 할 수도 있고 그렇지 않을 수도 있습니다. CPython의 많은 객체 유형의 경우 refcount는 "객체의 데이터 대량으로 저장"되지 않습니다. 어쨌든 COW는 원래 exec-after-fork를 구현하기 위해 고안되었지만 이점은 방대한 부모 프로세스 데이터가 결코 참조되지 않는다는 것입니다. –