2012-02-20 6 views
6

Tôi có một lồng nhau cho vòng lặp trong mã python của tôi trông giống như thế này:parallelise lồng cho vòng lặp trong IPython

results = [] 

for azimuth in azimuths: 
    for zenith in zeniths: 
     # Do various bits of stuff 
     # Eventually get a result 
     results.append(result) 

Tôi muốn parallelise vòng lặp này trên máy 4 nòng cốt của tôi để tăng tốc độ nó lên . Nhìn vào tài liệu lập trình song song IPython (http://ipython.org/ipython-doc/dev/parallel/parallel_multiengine.html#quick-and-easy-parallelism) dường như có một cách dễ dàng để sử dụng map để lặp lại song song hoạt động.

Tuy nhiên, để thực hiện điều đó, tôi cần phải có mã bên trong vòng lặp làm chức năng (dễ thực hiện) và sau đó ánh xạ qua chức năng này. Vấn đề tôi có là tôi không thể có được một mảng để ánh xạ chức năng này. itertools.product() tạo một trình lặp mà tôi không thể sử dụng chức năng bản đồ.

Tôi có đang sủa nhầm cây bằng cách cố gắng sử dụng bản đồ ở đây không? Có cách nào tốt hơn để làm điều đó không? Hoặc là có một số cách để sử dụng itertools.product và sau đó thực hiện song song với một chức năng ánh xạ trên các kết quả?

+0

chức năng bản đồ Clojure của hoạt động trên trình tự, và trong khi hầu hết các chuỗi là container, thực sự chỉ là của mình một giao diện mà bất cứ điều gì có thể thực hiện. Có điều gì giống như bạn có thể tận dụng lợi thế của (sắt) Python? – Bill

+0

Điều gì xảy ra khi bạn thử 'itertools.product'? Điều đó dường như là cách để làm điều đó. –

+0

'itertools.product' có vẻ là tuyệt vời cho việc tạo ra một trình lặp trên tất cả các kết hợp của góc phương vị và đỉnh số, nhưng tôi dường như không thể song song điều này. Bất kỳ ý tưởng làm thế nào để làm điều này? – robintw

Trả lời

10

Để song song mọi cuộc gọi, bạn chỉ cần có danh sách cho mỗi đối số. Bạn có thể sử dụng itertools.product + zip để có được điều này:

allzeniths, allazimuths = zip(*itertools.product(zeniths, azimuths)) 

Sau đó, bạn có thể sử dụng bản đồ:

amr = dview.map(f, allzeniths, allazimuths) 

Để đi một chút sâu hơn vào các bước, sau đây là một ví dụ:

zeniths = range(1,4) 
azimuths = range(6,8) 

product = list(itertools.product(zeniths, azimuths)) 
# [(1, 6), (1, 7), (2, 6), (2, 7), (3, 6), (3, 7)] 

Vì vậy, chúng tôi có một "danh sách các cặp", nhưng những gì chúng tôi thực sự muốn là một danh sách duy nhất cho mỗi đối số, tức là một "cặp danh sách". Đây là chính xác những gì zip(*product) cú pháp hơi kỳ lạ được chúng tôi:

allzeniths, allazimuths = zip(*itertools.product(zeniths, azimuths)) 

print allzeniths 
# (1, 1, 2, 2, 3, 3) 
print allazimuths 
# (6, 7, 6, 7, 6, 7) 

Bây giờ chúng tôi chỉ bản đồ chức năng của chúng tôi vào hai danh sách, để parallelize lồng nhau cho vòng:

def f(z,a): 
    return z*a 

view.map(f, allzeniths, allazimuths) 

Và không có gì đặc biệt về có bị chỉ có hai - phương pháp này nên mở rộng đến một số tùy ý của vòng lặp lồng nhau.

1

Tôi không thực sự quen thuộc với IPython, nhưng giải pháp dễ dàng dường như chỉ song song với vòng ngoài.

def f(azimuth): 
    results = [] 
    for zenith in zeniths: 
     #compute result 
     results.append(result) 
    return results 

allresults = map(f, azimuths) 
8

Tôi giả sử bạn đang sử dụng IPython 0,11 trở lên. Trước hết xác định một hàm đơn giản.

def foo(azimuth, zenith): 
    # Do various bits of stuff 
    # Eventually get a result 
    return result 

sau đó sử dụng bộ song song tốt của IPython để song song vấn đề của bạn. đầu tiên bắt đầu một bộ điều khiển với 5 động cơ gắn liền (#CPUs + 1) bằng cách bắt đầu một cụm trong một cửa sổ terminal (nếu bạn cài đặt IPython 0.11 hay muộn chương trình này nên có mặt):

ipcluster start -n 5 

Trong kịch bản của bạn kết nối với điều khiển và truyền tải tất cả các nhiệm vụ của bạn. Bộ điều khiển sẽ xử lý mọi thứ.

from IPython.parallel import Client 

c = Client() # here is where the client establishes the connection 
lv = c.load_balanced_view() # this object represents the engines (workers) 

tasks = [] 
for azimuth in azimuths: 
    for zenith in zeniths: 
     tasks.append(lv.apply(foo, azimuth, zenith)) 

result = [task.get() for task in tasks] # blocks until all results are back 
+0

Với ví dụ này, bạn nhận được một lỗi được ném về kết quả chung chưa được xác định. Tôi giả sử nhiều bộ vi xử lý không thấy kết quả. Cách chia sẻ? –

+0

@ john-m Tôi đã viết điều này cách đây 4 năm. Tại thời điểm này, IPython ở phiên bản 0.11. Hiện tại họ đang ở mức 4.x, tôi tin. Ví dụ của tôi có thể đã lỗi thời. Cộng với tôi đã không sử dụng IPython trong nhiều năm. – koloman

1

Nếu bạn thực sự muốn chạy mã của bạn song song, sử dụng concurrent.futures

import itertools 
import concurrent.futures 

def _work_horse(azimuth, zenith): 
    #DO HEAVY WORK HERE 
    return result 

futures = [] 
with concurrent.futures.ProcessPoolExecutor() as executor: 
    for arg_set in itertools.product(zeniths, azimuths): 
     futures.append(executor.submit(_work_horse, *arg_set)) 
executor.shutdown(wait=True) 

# Will time out after one hour. 
results = [future.result(3600) for future in futures]