Làm thế nào để thực hiện song song, trì hoãn theo cách mà vòng lặp song song cho dừng lại khi đầu ra xuống dưới ngưỡng?


8

Giả sử tôi có đoạn mã sau:

from scipy import *
import multiprocessing as mp
num_cores = mp.cpu_count()
from joblib import Parallel, delayed
import matplotlib.pyplot as plt

def func(x,y):
    return y/x
def main(y, xmin,xmax, dx):
    x = arange(xmin,xmax,dx)
    output = Parallel(n_jobs=num_cores)(delayed(func)(i, y) for i in x)
    return x, asarray(output)
def demo():
    x,z = main(2.,1.,30.,.1)
    plt.plot(x,z, label='All values')
    plt.plot(x[z>.1],z[z>.1], label='desired range') ## This is better to do in main()
    plt.show()

demo()

Tôi muốn chỉ tính toán đầu ra cho đến khi đầu ra> một số đã cho (có thể giả định rằng các phần tử đầu ra giảm đơn điệu khi tăng x) và sau đó dừng lại (KHÔNG tính cho tất cả các giá trị của x và sau đó sắp xếp, điều đó không hiệu quả cho mục đích của tôi). Có cách nào để làm điều đó bằng cách sử dụng Parallel, trì hoãn hoặc bất kỳ đa xử lý nào khác không?


Bạn cũng có thể sử dụng numpy. Tôi đã thêm vài con số. Việc lựa chọn [z> .1] trong chức năng demo phải được thực hiện trong chức năng chính để làm cho mã hiệu quả hơn.
dùng248534

Tôi biết nó sẽ lộn xộn nhưng tôi sẽ tạo một danh sách, chuyển nó vào hàm và hàm sẽ nối kết quả vào danh sách đó. Sau đó, bên ngoài tôi sẽ kiểm tra xem danh sách có chứa một số cao hơn số đó hay không và sau đó chấm dứt các chủ đề. Bây giờ tôi nghĩ về điều này có lẽ có các phương pháp thông minh hơn để làm điều này như Hàng đợi
Maxxik CZ

Câu trả lời:


1

Không có output > a given numberchỉ định nên tôi chỉ cần làm một. Sau khi thử nghiệm tôi đã phải đảo ngược điều kiện để hoạt động đúng output < a given number.

Tôi sẽ sử dụng một nhóm, khởi chạy các quy trình với chức năng gọi lại để kiểm tra điều kiện dừng, sau đó chấm dứt nhóm khi sẵn sàng. nhưng điều đó sẽ gây ra một điều kiện cuộc đua cho phép bỏ qua các kết quả khỏi quá trình đang chạy mà không được phép kết thúc. Tôi nghĩ rằng phương pháp này có sửa đổi tối thiểu cho mã của bạn và rất dễ đọc. Thứ tự của danh sách KHÔNG được đảm bảo.

Ưu điểm: rất ít chi phí
Nhược điểm: có thể thiếu kết quả.

Phương pháp 1)

from scipy import *
import multiprocessing

import matplotlib.pyplot as plt


def stop_condition_callback(ret):
        output.append(ret)
        if ret < stop_condition:
            worker_pool.terminate()


def func(x, y, ):
    return y / x


def main(y, xmin, xmax, dx):
    x = arange(xmin, xmax, dx)
    print("Number of calculations: %d" % (len(x)))

    # add calculations to the pool
    for i in x:
        worker_pool.apply_async(func, (i, y,), callback=stop_condition_callback)

    # wait for the pool to finish/terminate
    worker_pool.close()
    worker_pool.join()

    print("Number of results: %d" % (len(output)))
    return x, asarray(output)


def demo():
    x, z_list = main(2., 1., 30., .1)
    plt.plot(z_list, label='desired range')
    plt.show()


output = []
stop_condition = 0.1

worker_pool = multiprocessing.Pool()
demo()

Phương pháp này có nhiều chi phí hơn nhưng sẽ cho phép các quá trình đã bắt đầu kết thúc. Phương pháp 2)

from scipy import *
import multiprocessing

import matplotlib.pyplot as plt


def stop_condition_callback(ret):
    if ret is not None:
        if ret < stop_condition:
            worker_stop.value = 1
        else:
            output.append(ret)


def func(x, y, ):
    if worker_stop.value != 0:
        return None
    return y / x


def main(y, xmin, xmax, dx):
    x = arange(xmin, xmax, dx)
    print("Number of calculations: %d" % (len(x)))

    # add calculations to the pool
    for i in x:
        worker_pool.apply_async(func, (i, y,), callback=stop_condition_callback)

    # wait for the pool to finish/terminate
    worker_pool.close()
    worker_pool.join()

    print("Number of results: %d" % (len(output)))
    return x, asarray(output)


def demo():
    x, z_list = main(2., 1., 30., .1)
    plt.plot(z_list, label='desired range')
    plt.show()


output = []
worker_stop = multiprocessing.Value('i', 0)
stop_condition = 0.1

worker_pool = multiprocessing.Pool()
demo()

Phương pháp 3) Ưu điểm: Không có kết quả nào bị bỏ qua
Nhược điểm: Bước này nằm ngoài những gì bạn thường làm.

lấy Phương thức 1 và thêm

def stopPoolButLetRunningTaskFinish(pool):
    # Pool() shutdown new task from being started, by emptying the query all worker processes draw from
    while pool._task_handler.is_alive() and pool._inqueue._reader.poll():
        pool._inqueue._reader.recv()
    # Send sentinels to all worker processes
    for a in range(len(pool._pool)):
            pool._inqueue.put(None)

Sau đó thay đổi stop_condition_callback

def stop_condition_callback(ret):
    if ret[1] < stop_condition:
        #worker_pool.terminate()
        stopPoolButLetRunningTaskFinish(worker_pool)
    else:
        output.append(ret)

0

Tôi sẽ sử dụng Dask để thực thi song song và cụ thể là giao diện tương lai cho phản hồi thời gian thực về kết quả khi chúng được hoàn thành. Khi hoàn tất, bạn có thể hủy các hợp đồng tương lai còn lại trong chuyến bay, thuê những thứ không cần thiết để hoàn thành không đồng bộ hoặc đóng cụm.

from dask.distributed import Client, as_completed
client = Client()  # defaults to ncores workers, one thread each
y, xmin, xmax, dx = 2.,1.,30.,.1

def func(x, y):
    return x, y/x
x = arange(xmin,xmax,dx)
outx = []
output = []
futs = [client.submit(func, val, y) for val in x]
for future in as_completed(futs):
    outs = future.result()
    outx.append(outs[0])
    output.append(outs[1])
    if outs[1] < 0.1:
        break

Lưu ý: - Tôi giả sử bạn có nghĩa là "ít hơn", vì nếu không thì giá trị đầu tiên đã vượt qua ( y / xmin > 0.1) - các đầu ra không được đảm bảo theo thứ tự bạn nhập chúng nếu bạn muốn tìm nạp kết quả khi chúng sẵn sàng, nhưng với như vậy tính toán nhanh, có lẽ chúng luôn như vậy (đây là lý do tại sao tôi cũng có func trả về giá trị đầu vào) - nếu bạn dừng tính toán, đầu ra sẽ ngắn hơn toàn bộ đầu vào, vì vậy tôi không chắc bạn muốn gì in.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.