2012-06-30 31 views
6

Tôi đang cố gắng mô phỏng một mạng các ứng dụng chạy bằng cách sử dụng xoắn. Là một phần của mô phỏng của tôi, tôi muốn đồng bộ hóa một số sự kiện nhất định và có thể cho mỗi quá trình xử lý một lượng lớn dữ liệu. Tôi đã quyết định sử dụng Sự kiện và Hàng đợi đa xử lý. Tuy nhiên, các quy trình của tôi đang bị treo.bị xoắn không tương thích với các sự kiện đa xử lý và hàng đợi?

Tôi đã viết mã ví dụ bên dưới để minh họa sự cố. Cụ thể, (khoảng 95% thời gian trên máy cầu cát của tôi), chức năng 'run_in_thread' kết thúc, tuy nhiên cuộc gọi lại 'print_done' không được gọi cho đến sau khi tôi nhấn Ctrl-C.

Ngoài ra, tôi có thể thay đổi một số điều trong mã ví dụ để làm cho công việc này đáng tin cậy hơn như: giảm số lượng các quá trình sinh sản, gọi self.ready.set từ reactor_ready hoặc thay đổi độ trễ của deferLater.

Tôi đoán có điều kiện chạy đua ở đâu đó giữa lò phản ứng xoắn và chặn các cuộc gọi đa xử lý như Queue.get() hoặc Event.wait()?

Chính xác thì vấn đề tôi đang gặp phải là gì? Có một lỗi trong mã của tôi mà tôi đang thiếu? Tôi có thể sửa lỗi này hoặc bị xoắn không tương thích với các sự kiện/hàng đợi đa xử lý không?

Thứ hai, điều gì đó giống như spawnProcess hoặc Ampoule là giải pháp thay thế được đề xuất? (Như đề xuất trong Mix Python Twisted with multiprocessing?)

Chỉnh sửa (theo yêu cầu):

Tôi đã gặp vấn đề với tất cả các lò phản ứng tôi đã cố gắng glib2reactor selectreactor, pollreactor, và epollreactor. Các epollreactor dường như cho kết quả tốt nhất và dường như làm việc tốt cho ví dụ dưới đây nhưng vẫn mang lại cho tôi cùng một (hoặc tương tự) vấn đề trong ứng dụng của tôi. Tôi sẽ tiếp tục điều tra.

Tôi đang chạy Gentoo Linux kernel 3.3 và 3.4, python 2.7 và tôi đã thử Twisted 10.2.0, 11.0.0, 11.1.0, 12.0.0 và 12.1.0.

Ngoài máy cầu cát của tôi, tôi thấy cùng một vấn đề trên máy tính lõi kép của tôi.

#!/usr/bin/python 
# -*- coding: utf-8 *-* 

from twisted.internet import reactor 
from twisted.internet import threads 
from twisted.internet import task 

from multiprocessing import Process 
from multiprocessing import Event 

class TestA(Process): 
    def __init__(self): 
     super(TestA, self).__init__() 
     self.ready = Event() 
     self.ready.clear() 
     self.start() 

    def run(self): 
     reactor.callWhenRunning(self.reactor_ready) 
     reactor.run() 

    def reactor_ready(self, *args): 
     task.deferLater(reactor, 1, self.node_ready) 
     return args 

    def node_ready(self, *args): 
     print 'node_ready' 
     self.ready.set() 
     return args 

def reactor_running(): 
    print 'reactor_running' 
    df = threads.deferToThread(run_in_thread) 
    df.addCallback(print_done) 

def run_in_thread(): 
    print 'run_in_thread' 
    for n in processes: 
     n.ready.wait() 

def print_done(dfResult=None): 
    print 'print_done' 
    reactor.stop() 

if __name__ == '__main__': 
    processes = [TestA() for i in range(8)] 
    reactor.callWhenRunning(reactor_running) 
    reactor.run() 
+0

Các chi tiết chính xác về phiên bản Twisted bạn đang sử dụng, hệ điều hành nào bạn đang chạy, lò phản ứng bạn đang sử dụng (et cetera) sẽ hữu ích khi trả lời câu hỏi này. – Glyph

+0

Tôi đã gặp vấn đề với tất cả các lò phản ứng mà tôi đã thử glib2reactor selectreactor, pollreactor, và epollreactor. Tôi đang chạy Gentoo Linux, python 2.7 và tôi đã thử Twisted 11.1.0, 12.0.0 và 12.1.0. – Agrajag

Trả lời

10

Câu trả lời ngắn gọn là có, Xoắn và đa xử lý không tương thích với nhau và bạn không thể sử dụng chúng một cách đáng tin cậy như bạn đang cố gắng.

Trên tất cả các nền tảng POSIX, quản lý quy trình con được gắn chặt với việc xử lý SIGCHLD. Bộ xử lý tín hiệu POSIX xử lý toàn cầu và chỉ có thể có một loại cho mỗi loại tín hiệu.

Xoắn và stdlib multiprocessing không thể vừa cài đặt bộ xử lý SIGCHLD. Chỉ một trong số họ có thể. Điều đó có nghĩa là chỉ một trong số họ có thể quản lý các quy trình con một cách đáng tin cậy. Ứng dụng ví dụ của bạn không kiểm soát cái nào trong số chúng sẽ giành được khả năng đó, vì vậy tôi mong đợi sẽ có một số tính không xác định trong hành vi của nó phát sinh từ thực tế đó.

Tuy nhiên, vấn đề ngay lập tức với ví dụ của bạn là bạn tải Twisted trong quá trình cha mẹ và sau đó sử dụng multiprocessing để fork và không exec tất cả các quy trình con. Xoắn không hỗ trợ được sử dụng như thế này. Nếu bạn ngã ba và sau đó exec, không có vấn đề gì. Tuy nhiên, việc thiếu một exec của một quá trình mới (có lẽ một quá trình Python sử dụng Twisted) dẫn đến tất cả các loại trạng thái chia sẻ thêm mà Twisted không tính đến.Trong trường hợp cụ thể của bạn, trạng thái chia sẻ gây ra sự cố này là "waker fd" nội bộ được sử dụng để triển khai deferToThread. Với fd được chia sẻ giữa phụ huynh và tất cả các trẻ em, khi phụ huynh cố gắng đánh thức luồng chính để cung cấp kết quả cuộc gọi deferToThread, rất có thể nó sẽ đánh thức một trong các quy trình con thay vì. Quá trình con không có gì hữu ích để làm, vì vậy đó chỉ là một sự lãng phí thời gian. Trong khi đó các chủ đề chính trong phụ huynh không bao giờ tỉnh dậy và không bao giờ nhận thấy công việc luồng của bạn được thực hiện.

Có thể bạn có thể tránh vấn đề này bằng cách không tải bất kỳ Twisted nào cho đến khi bạn đã tạo quy trình con. Điều này sẽ biến việc sử dụng của bạn thành một trường hợp sử dụng đơn lẻ theo như Twisted là có liên quan (trong mỗi quá trình, nó sẽ được nạp ban đầu, và sau đó quá trình đó sẽ không phải là đi đến ngã ba, vì vậy không có câu hỏi làm thế nào ngã ba và Twisted tương tác nữa). Điều này có nghĩa là thậm chí không nhập Twisted cho đến khi bạn đã tạo các tiến trình con.

Tất nhiên, điều này chỉ giúp bạn ra xa như Twisted đi. Bất kỳ thư viện nào khác mà bạn sử dụng có thể gặp rắc rối tương tự (bạn đã đề cập glib2, đó là một ví dụ tuyệt vời về một thư viện khác sẽ hoàn toàn bị nghẹt thở nếu bạn cố sử dụng nó như thế này).

Tôi thực sự khuyên bạn không nên sử dụng mô-đun multiprocessing. Thay vào đó, hãy sử dụng bất kỳ phương pháp tiếp cận đa quy trình nào liên quan đến ngã ba exec, chứ không phải ngã ba một mình. Ampoule rơi vào loại đó.

+0

Cảm ơn bạn đã giải thích chi tiết. Tất cả các vấn đề dường như hiển nhiên bây giờ! Tôi quản lý để có được mô phỏng của tôi chạy tuyệt vời bằng cách sử dụng subprocess.Popen, và một multiprocessing.connection Listener/Client (sử dụng AF_UNIX) để tạo thuận lợi cho communcation/đồng bộ giữa các nút xoắn và quá trình điều khiển. Cảm ơn một lần nữa! – Agrajag

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