Tại sao đa xử lý chỉ sử dụng một lõi sau khi tôi nhập numpy?


127

Tôi không chắc liệu đây có phải là vấn đề của hệ điều hành hay không, nhưng tôi nghĩ tôi sẽ hỏi ở đây trong trường hợp bất cứ ai có cái nhìn sâu sắc từ phần cuối của Python.

Tôi đã cố gắng song song hóa một forvòng lặp nặng CPU joblib, nhưng tôi thấy rằng thay vì mỗi quy trình công nhân được gán cho một lõi khác nhau, tôi kết thúc với tất cả chúng được gán cho cùng một lõi và không tăng hiệu năng.

Đây là một ví dụ rất tầm thường ...

from joblib import Parallel,delayed
import numpy as np

def testfunc(data):
    # some very boneheaded CPU work
    for nn in xrange(1000):
        for ii in data[0,:]:
            for jj in data[1,:]:
                ii*jj

def run(niter=10):
    data = (np.random.randn(2,100) for ii in xrange(niter))
    pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all')
    results = pool(delayed(testfunc)(dd) for dd in data)

if __name__ == '__main__':
    run()

... Và đây là những gì tôi thấy trong htopkhi tập lệnh này đang chạy:

đỉnh

Tôi đang chạy Ubuntu 12.10 (3.5.0-26) trên máy tính xách tay có 4 lõi. Rõ ràng joblib.Parallellà sinh ra các quy trình riêng biệt cho các công nhân khác nhau, nhưng có cách nào để tôi có thể thực hiện các quy trình này trên các lõi khác nhau không?


stackoverflow.com/questions/15168014/ - không có câu trả lời nào tôi sợ, nhưng có vẻ như vấn đề tương tự.
NPE



Đây vẫn là một vấn đề? Tôi đang cố gắng tạo lại điều này với Python 3.7 và nhập numpy với đa xử lý.Pool () và nó sử dụng tất cả các luồng (nếu cần). Chỉ muốn đảm bảo rằng điều này đã được sửa chữa.
Jared Nielsen

Câu trả lời:


148

Sau khi thêm một số googling tôi tìm thấy câu trả lời ở đây .

Nó chỉ ra rằng một số module Python ( numpy, scipy, tables, pandas, skimage...) gây rối với ái lực cốt lõi về nhập khẩu. Theo như tôi có thể nói, vấn đề này dường như được gây ra bởi chúng liên kết với các thư viện OpenBLAS đa luồng.

Một cách giải quyết là đặt lại mối quan hệ nhiệm vụ bằng cách sử dụng

os.system("taskset -p 0xff %d" % os.getpid())

Với dòng này được dán sau khi nhập mô-đun, ví dụ của tôi bây giờ chạy trên tất cả các lõi:

htop_workaround

Kinh nghiệm của tôi cho đến nay là điều này dường như không có bất kỳ ảnh hưởng tiêu cực nào đến hiệu numpysuất của nó, mặc dù điều này có lẽ là máy móc và nhiệm vụ cụ thể.

Cập nhật:

Cũng có hai cách để vô hiệu hóa hành vi thiết lập lại mối quan hệ CPU của chính OpenBLAS. Tại thời gian chạy, bạn có thể sử dụng biến môi trường OPENBLAS_MAIN_FREE(hoặc GOTOBLAS_MAIN_FREE), ví dụ

OPENBLAS_MAIN_FREE=1 python myscript.py

Hoặc cách khác, nếu bạn đang biên dịch OpenBLAS từ nguồn, bạn có thể vô hiệu hóa nó vĩnh viễn tại thời điểm xây dựng bằng cách chỉnh sửa Makefile.ruleđể chứa dòng

NO_AFFINITY=1

Cảm ơn, giải pháp của bạn đã giải quyết vấn đề. Một câu hỏi, tôi có cùng mã nhưng chạy khác nhau trên máy kéo khác nhau. Cả hai máy đều là Ubuntu 12.04 LTS, python 2.7, nhưng chỉ có một máy có vấn đề này. Bạn có biết tại sao không?
iampat

Cả hai máy đều có OpenBLAS (bản dựng với OpenMPI).
iampat

2
Chủ đề cũ, nhưng trong trường hợp bất kỳ ai khác tìm thấy vấn đề này, tôi đã có vấn đề chính xác và nó thực sự có liên quan đến các thư viện OpenBLAS. Xem ở đây cho hai cách giải quyết có thể và một số thảo luận liên quan.
Gabriel

2
Một cách khác để thiết lập mối quan hệ cpu là sử dụngpsutil .
Ioannis Filippidis

2
@JHG Đó là một vấn đề với OpenBLAS chứ không phải Python, vì vậy tôi không thể thấy bất kỳ lý do nào khiến phiên bản Python tạo ra sự khác biệt
ali_m

27

Python 3 hiện hiển thị các phương thức để đặt trực tiếp mối quan hệ

>>> import os
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}
>>> os.sched_setaffinity(0, {1, 3})
>>> os.sched_getaffinity(0)
{1, 3}
>>> x = {i for i in range(10)}
>>> x
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> os.sched_setaffinity(0, x)
>>> os.sched_getaffinity(0)
{0, 1, 2, 3}

1
Lỗi> AttributionError: mô-đun 'os' không có thuộc tính 'calendar_getaffinity', Python 3.6
Paddy

4
@Paddy Từ tài liệu được liên kết: Chúng chỉ có sẵn trên một số nền tảng Unix.
BlackJack

2
Tôi có cùng một vấn đề nhưng tôi đã tích hợp cùng dòng này ở hệ điều hành hàng đầu ("tasket -p 0xff% d"% os.getpid ()) nhưng nó không sử dụng tất cả cpu
rajeshcis

12

Đây dường như là một vấn đề phổ biến với Python trên Ubuntu và không cụ thể đối với joblib:

Tôi sẽ đề nghị thử nghiệm với ái lực CPU ( taskset).


Python on UbuntuĐiều này ngụ ý rằng nó hoạt động mà không gặp sự cố trên Windows và hệ điều hành khác. Là nó?
Cột
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.