2015-07-27 24 views
9

Tôi đang sử dụng chức năng đa xử lý python để ánh xạ một số chức năng trên một số thành phần. Một cái gì đó dọc theo dòng này:Tại sao công nhân đa xử lý Python không chết?

def computeStuff(arguments, globalData, concurrent=True): 
    pool = multiprocessing.Pool(initializer=initWorker, initargs=(globalData,)) 
    results = pool.map(workerFunction, list(enumerate(arguments))) 
    return results 

def initWorker(globalData): 
    workerFunction.globalData = globalData 

def workerFunction((index, argument)): 
    ... # computation here 

Nói chung tôi chạy thử nghiệm trong ipython sử dụng cả hai CPython và PyPy. Tôi đã nhận thấy rằng các quá trình sinh sản thường không bị giết, do đó, họ bắt đầu tích lũy, từng sử dụng một gig của ram. Điều này xảy ra khi nhấn ctrl-k trong quá trình tính toán, điều này sẽ gửi đa xử lý thành một sự bối rối lớn. Nhưng ngay cả khi để kết thúc tính toán, các quy trình đó sẽ không chết trong Pypy.

Theo tài liệu, khi hồ bơi bị thu gom rác, cần gọi terminate() và tiêu diệt tất cả các quy trình. Điều gì đang xảy ra ở đây? Tôi có phải gọi một cách rõ ràng close() không? Nếu có, có một số loại trình quản lý ngữ cảnh quản lý đúng cách đóng tài nguyên (tức là quy trình) không?

Đây là trên Mac OS X Yosemite.

+7

upvote cho tiêu đề tư bản thực sự – percusse

+1

Có thể bạn chỉ cần thêm '' try: ... final: pool.terminate() ''? –

+0

Có lẽ câu hỏi của tôi không rõ ràng - Tôi đang nói rằng người lao động ở lại ngay cả khi tính toán kết thúc. Mặc dù họ không nên, nếu tôi hiểu tài liệu một cách chính xác, trong mọi trường hợp. – Ant6n

Trả lời

2

Bộ sưu tập rác của PyPy là lười, do đó, không gọi close có nghĩa là Pool được làm sạch "đôi khi", nhưng điều đó có thể không có nghĩa là "sớm".

Khi Pool đúng cách close d, công nhân sẽ thoát khi hết nhiệm vụ. Một cách dễ dàng để đảm bảo Pool đóng cửa vào trước 3.3 Python là:

from contextlib import closing 

def computeStuff(arguments, globalData, concurrent=True): 
    with closing(multiprocessing.Pool(initializer=initWorker, initargs=(globalData,))) as pool: 
     return pool.map(workerFunction, enumerate(arguments)) 

Lưu ý: Tôi cũng loại bỏ việc chuyển đổi rõ ràng để list (vô nghĩa, vì map sẽ lặp các enumerate iterator cho bạn), và trả lại kết quả trực tiếp (không cần chỉ định cho một tên để trả về dòng tiếp theo).

Nếu bạn muốn đảm bảo chấm dứt ngay lập tức trong trường hợp ngoại lệ (trên Python trước 3.3), bạn sử dụng khối thử/cuối cùng hoặc viết trình quản lý ngữ cảnh đơn giản (có thể được sử dụng lại cho các địa điểm khác mà bạn sử dụng một Pool):

from contextlib import contextmanager 

@contextmanager 
def terminating(obj): 
    try: 
     yield obj 
    finally: 
     obj.terminate() 

def computeStuff(arguments, globalData, concurrent=True): 
    with terminating(multiprocessing.Pool(initializer=initWorker, initargs=(globalData,))) as pool: 
     return pool.map(workerFunction, enumerate(arguments)) 

cách tiếp cận terminating là vượt trội ở chỗ nó đảm bảo lối ra quá trình ngay lập tức; về lý thuyết, nếu bạn đang sử dụng các chủ đề ở đâu đó trong chương trình chính của bạn, các công nhân Pool có thể được chia nhỏ với các chuỗi không phải daemon, điều này sẽ giữ cho các tiến trình còn sống ngay cả khi chuỗi nhiệm vụ của nhân viên đã thoát; terminating giấu điều này bằng cách giết chết các quy trình cưỡng bức.

Nếu thông dịch của bạn là Python 3.3 hoặc cao hơn, cách tiếp cận terminating được xây dựng-in để Pool, vì vậy không wrapper đặc biệt là cần thiết cho báo cáo kết quả with, with multiprocessing.Pool(initializer=initWorker, initargs=(globalData,)) as pool: công trình trực tiếp.

+0

rất đẹp, thx! – Ant6n

Các vấn đề liên quan