2009-07-25 44 views
24

Tôi đã đọc về số multiprocessing module của Python. Tôi vẫn không nghĩ rằng tôi có một sự hiểu biết rất tốt về những gì nó có thể làm.Python: Xử lý đa lõi?

Giả sử tôi có bộ xử lý lõi tứ và tôi có danh sách với 1.000.000 số nguyên và tôi muốn tổng của tất cả các số nguyên. Tôi có thể chỉ cần làm:

list_sum = sum(my_list) 

Nhưng điều này chỉ gửi đến một lõi.

Có thể sử dụng mô-đun đa xử lý để chia mảng và có mỗi lõi lấy tổng của nó và trả về giá trị sao cho tổng số tiền có thể được tính toán?

Cái gì như:

core1_sum = sum(my_list[0:500000])   #goes to core 1 
core2_sum = sum(my_list[500001:1000000]) #goes to core 2 
all_core_sum = core1_sum + core2_sum  #core 3 does final computation 

Bất kỳ trợ giúp sẽ được đánh giá cao.

Trả lời

30

Vâng, nó có thể làm tổng kết này qua nhiều quy trình, rất giống với làm việc đó với nhiều chủ đề:

from multiprocessing import Process, Queue 

def do_sum(q,l): 
    q.put(sum(l)) 

def main(): 
    my_list = range(1000000) 

    q = Queue() 

    p1 = Process(target=do_sum, args=(q,my_list[:500000])) 
    p2 = Process(target=do_sum, args=(q,my_list[500000:])) 
    p1.start() 
    p2.start() 
    r1 = q.get() 
    r2 = q.get() 
    print r1+r2 

if __name__=='__main__': 
    main() 

Tuy nhiên , có khả năng làm việc đó với nhiều quy trình có khả năng chậm hơn so với thực hiện nó trong một quy trình duy nhất, vì sao chép dữ liệu ra và ngược lại đắt hơn so với tổng hợp chúng ngay lập tức.

+1

@Martin, tôi tin rằng những bế tắc này, theo http://docs.python.org/library/multiprocessing.html#multiprocessing-programming: "một quá trình đã đặt các mục vào một hàng đợi sẽ đợi trước khi chấm dứt cho đến khi tất cả các mục đệm được nạp bởi luồng "feeder" vào đường ống bên dưới "- ví dụ về bế tắc mà tài liệu cung cấp rất giống với mã của bạn (đó là một tiến trình con duy nhất trong phần bắt đầu, tham gia, nhận trình tự) và hai quy trình con thay vì một quy trình không hữu ích. Hoán đổi các kết nối và nhận hoặc chỉ xóa các kết nối. –

+0

"Nó làm việc cho tôi", có lẽ vì dữ liệu chỉ đơn giản là phù hợp với đường ống. Trong mọi trường hợp, tôi đã xóa các kết nối. –

+0

Bạn có đang chạy trên Linux không? – Nope

20

Chào mừng thế giới lập trình đồng thời.

Điều mà Python có thể (và không thể) phụ thuộc vào hai điều.

  1. Hệ điều hành có thể (và không thể) làm. Hầu hết các hệ điều hành phân bổ các quy trình cho lõi. Để sử dụng 4 lõi, bạn cần phải giải quyết vấn đề của mình thành bốn quy trình. Điều này dễ hơn âm thanh. Đôi khi.

  2. Thư viện C cơ bản có thể (và không thể) làm. Nếu các thư viện C phơi bày các tính năng của hệ điều hành và hệ điều hành cho thấy các tính năng của phần cứng, bạn chắc chắn.

Để giải quyết vấn đề thành nhiều quy trình - đặc biệt trong GNU/Linux - thật dễ dàng. Chia nó thành một đường ống đa bước.

Trong trường hợp tổng hợp một triệu số, hãy nghĩ về tập lệnh trình bao sau. Giả sử một số chương trình giả thuyết sum.py tổng hợp một loạt các số hoặc danh sách các số trên stdin.

(sum.py 0 500000 & sum.py 50000 1000000) | sum.py

Điều này sẽ có 3 quy trình đồng thời. Hai là làm tổng của rất nhiều con số, thứ ba là tổng hợp hai con số.

Vì vỏ GNU/Linux và hệ điều hành đã xử lý một số phần đồng thời cho bạn, bạn có thể thiết kế các chương trình đơn giản (rất, rất đơn giản) đọc từ stdin, viết thành stdout và được thiết kế để thực hiện các phần nhỏ một công việc lớn.

Bạn có thể thử giảm chi phí bằng cách sử dụng subprocess để tạo đường ống thay vì phân bổ công việc cho trình bao. Tuy nhiên, bạn có thể thấy rằng vỏ xây dựng đường ống rất, rất nhanh. (. Nó được viết trực tiếp trong C và làm cho các cuộc gọi hệ điều hành API trực tiếp cho bạn)

+0

Tôi cảm thấy câu trả lời này cho thấy rất nhiều sự khéo léo. Không có vấn đề trong CS không thể được giải quyết bằng cách đơn giản thêm một lớp indirection. – earino

+0

@earino: OTOH, nó hoàn toàn không trả lời câu hỏi của OP, mà cụ thể là "làm cách nào để sử dụng mô-đun đa xử lý". –

+2

@Martin v. Löwis: Đúng vậy. IMO vấn đề lớn hơn (sử dụng tất cả các lõi) thường quan trọng hơn câu hỏi được yêu cầu (sử dụng tiến trình con để sử dụng tất cả các lõi). Trong một số trường hợp, câu hỏi được hỏi phản ánh một số giả định kém. –

7

Chắc chắn, ví dụ:

from multiprocessing import Process, Queue 

thelist = range(1000*1000) 

def f(q, sublist): 
    q.put(sum(sublist)) 

def main(): 
    start = 0 
    chunk = 500*1000 
    queue = Queue() 
    NP = 0 
    subprocesses = [] 
    while start < len(thelist): 
     p = Process(target=f, args=(queue, thelist[start:start+chunk])) 
     NP += 1 
     print 'delegated %s:%s to subprocess %s' % (start, start+chunk, NP) 
     p.start() 
     start += chunk 
     subprocesses.append(p) 
    total = 0 
    for i in range(NP): 
     total += queue.get() 
    print "total is", total, '=', sum(thelist) 
    while subprocesses: 
     subprocesses.pop().join() 

if __name__ == '__main__': 
    main() 

kết quả trong:

$ python2.6 mup.py 
delegated 0:500000 to subprocess 1 
delegated 500000:1000000 to subprocess 2 
total is 499999500000 = 499999500000 

lưu ý rằng chi tiết này là quá tốt để được quá trình sinh sản có giá trị cho - nhiệm vụ tổng hợp chung là nhỏ (đó là lý do tại sao tôi có thể tính toán tổng trong chính như một kiểm tra ;-) và quá nhiều dữ liệu đang được di chuyển qua lại (trong thực tế, các quy trình con sẽ không cần phải nhận được bản sao của sublists họ làm việc trên - chỉ số sẽ đủ). Vì vậy, đó là một "ví dụ đồ chơi" trong đó đa xử lý không thực sự được bảo đảm. Với các kiến ​​trúc khác nhau (sử dụng một nhóm các tiến trình con nhận nhiều nhiệm vụ để thực hiện từ hàng đợi, giảm thiểu chuyển động dữ liệu qua lại, vv ..) và các tác vụ ít chi tiết hơn, bạn thực sự có thể nhận được lợi ích về mặt hiệu suất.

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