2011-08-07 36 views
43

Có thể tạo một Hồ bơi python không phải là daemon không? Tôi muốn một hồ bơi để có thể gọi một chức năng có một hồ bơi bên trong. Cảm ơn.Quy trình Python Pool non-daemonic?

+0

AFAIK, không có nó không thể tất cả người lao động trong hồ bơi được daemonized và nó không thể __inject phụ thuộc__, BTW tôi không hiểu phần thứ hai của câu hỏi của bạn 'Tôi muốn một hồ bơi để có thể gọi một chức năng mà có một hồ bơi bên trong' và làm thế nào mà can thiệp vào thực tế là các công nhân được daemonized. – mouad

+1

Bởi vì nếu hàm a có một pool chạy hàm b có một pool chạy hàm c, có một vấn đề trong b rằng nó đang được chạy trong một quá trình daemon, và các quy trình daemon không thể tạo các tiến trình. 'AssertionError: quy trình daemon không được phép có con ' – Max

Trả lời

68

Lớp multiprocessing.pool.Pool tạo ra các quá trình lao động trong phương pháp __init__ của nó, làm cho chúng ma quỉ và bắt đầu họ, và nó không thể để tái thiết lập thuộc tính daemon của họ để False trước khi chúng được bắt đầu (và sau đó nó không cho phép nữa). Nhưng bạn có thể tạo một lớp con của riêng bạn là multiprocesing.pool.Pool (multiprocessing.Pool chỉ là một hàm bao bọc) và thay thế lớp con multiprocessing.Process của riêng bạn, mà luôn luôn không phải là daemonic, được sử dụng cho các quy trình công nhân.

Dưới đây là ví dụ đầy đủ về cách thực hiện việc này. Các phần quan trọng là hai lớp NoDaemonProcessMyPool ở trên cùng và gọi pool.close()pool.join() trên phiên bản MyPool của bạn ở cuối.

#!/usr/bin/env python 
# -*- coding: UTF-8 -*- 

import multiprocessing 
# We must import this explicitly, it is not imported by the top-level 
# multiprocessing module. 
import multiprocessing.pool 
import time 

from random import randint 


class NoDaemonProcess(multiprocessing.Process): 
    # make 'daemon' attribute always return False 
    def _get_daemon(self): 
     return False 
    def _set_daemon(self, value): 
     pass 
    daemon = property(_get_daemon, _set_daemon) 

# We sub-class multiprocessing.pool.Pool instead of multiprocessing.Pool 
# because the latter is only a wrapper function, not a proper class. 
class MyPool(multiprocessing.pool.Pool): 
    Process = NoDaemonProcess 

def sleepawhile(t): 
    print("Sleeping %i seconds..." % t) 
    time.sleep(t) 
    return t 

def work(num_procs): 
    print("Creating %i (daemon) workers and jobs in child." % num_procs) 
    pool = multiprocessing.Pool(num_procs) 

    result = pool.map(sleepawhile, 
     [randint(1, 5) for x in range(num_procs)]) 

    # The following is not really needed, since the (daemon) workers of the 
    # child's pool are killed when the child is terminated, but it's good 
    # practice to cleanup after ourselves anyway. 
    pool.close() 
    pool.join() 
    return result 

def test(): 
    print("Creating 5 (non-daemon) workers and jobs in main process.") 
    pool = MyPool(5) 

    result = pool.map(work, [randint(1, 5) for x in range(5)]) 

    pool.close() 
    pool.join() 
    print(result) 

if __name__ == '__main__': 
    test() 
+0

Đoạn mã trên dường như bị treo cho tôi. Cụ thể nó xuất hiện để treo tại pool.close() bên trong công việc(). Có điều gì tôi đang thiếu? –

+1

Tôi vừa thử nghiệm lại mã của mình bằng Python 2.7/3.2 (sau khi sửa các dòng "in") trên Linux và Python 2.6/2.7/3.2 OS X. Linux và Python 2.7/3.2 trên OS X hoạt động tốt nhưng mã thực sự treo với Python 2.6 trên OS X (Sư tử). Điều này có vẻ là một lỗi trong mô-đun đa xử lý, đã được khắc phục, nhưng tôi chưa thực sự kiểm tra trình theo dõi lỗi. –

+0

Điều này thực sự cần được khắc phục trong mô-đun đa xử lý (tùy chọn cho các công nhân không phải daemon có sẵn). Có ai biết ai duy trì nó không? –

6

Module multiprocessing có một giao diện đẹp để sử dụng hồ bơi với các quá trình hay đề. Tùy thuộc vào trường hợp sử dụng hiện tại của bạn, bạn có thể cân nhắc sử dụng multiprocessing.pool.ThreadPool cho hồ bơi ngoài của mình, điều này sẽ dẫn đến chủ đề (cho phép sinh ra các quy trình từ bên trong) trái với quy trình.

Nó có thể bị giới hạn bởi các GIL, nhưng trong trường hợp cụ thể của tôi (Tôi đã thử nghiệm cả hai), thời gian khởi động cho các quá trình từ bên ngoài Pool như tạo here nằm ngoài những giải pháp với ThreadPool.


Thật dễ dàng để hoán đổi Processes cho Threads. Đọc thêm về cách sử dụng giải pháp ThreadPoolhere hoặc here.

0

Vấn đề tôi gặp phải là cố gắng nhập hình cầu nối giữa các mô-đun, làm cho dòng ProcessPool() được đánh giá nhiều lần.

globals.py

from processing    import Manager, Lock 
from pathos.multiprocessing import ProcessPool 
from pathos.threading  import ThreadPool 

class SingletonMeta(type): 
    def __new__(cls, name, bases, dict): 
     dict['__deepcopy__'] = dict['__copy__'] = lambda self, *args: self 
     return super(SingletonMeta, cls).__new__(cls, name, bases, dict) 

    def __init__(cls, name, bases, dict): 
     super(SingletonMeta, cls).__init__(name, bases, dict) 
     cls.instance = None 

    def __call__(cls,*args,**kw): 
     if cls.instance is None: 
      cls.instance = super(SingletonMeta, cls).__call__(*args, **kw) 
     return cls.instance 

    def __deepcopy__(self, item): 
     return item.__class__.instance 

class Globals(object): 
    __metaclass__ = SingletonMeta 
    """  
    This class is a workaround to the bug: AssertionError: daemonic processes are not allowed to have children 

    The root cause is that importing this file from different modules causes this file to be reevalutated each time, 
    thus ProcessPool() gets reexecuted inside that child thread, thus causing the daemonic processes bug  
    """ 
    def __init__(self): 
     print "%s::__init__()" % (self.__class__.__name__) 
     self.shared_manager  = Manager() 
     self.shared_process_pool = ProcessPool() 
     self.shared_thread_pool = ThreadPool() 
     self.shared_lock   = Lock()  # BUG: Windows: global name 'lock' is not defined | doesn't affect cygwin 

Sau đó, nhập khẩu một cách an toàn từ nơi khác trong mã của bạn

from globals import Globals 
Globals().shared_manager  
Globals().shared_process_pool 
Globals().shared_thread_pool 
Globals().shared_lock