2014-05-08 19 views
5

Tôi đang gặp phải vấn đề kỳ lạ mà tôi không thể giải thích. Tôi hy vọng một người nào đó ra có thể giúp đỡ xin vui lòng!Nhập scipy ngắt hỗ trợ đa xử lý trong Python

Tôi đang chạy Python 2.7.3 và Scipy v0.14.0 và đang cố triển khai một số thuật toán đa xử lý rất đơn giản để tăng tốc mã của tôi bằng mô-đun multiprocessing. Tôi đã quản lý để thực hiện một ví dụ làm việc cơ bản:

import multiprocessing 
import numpy as np 
import time 
# import scipy.special 


def compute_something(t): 
    a = 0. 
    for i in range(100000): 
     a = np.sqrt(t) 
    return a 

if __name__ == '__main__': 

    pool_size = multiprocessing.cpu_count() 
    print "Pool size:", pool_size 
    pool = multiprocessing.Pool(processes=pool_size) 

    inputs = range(10) 

    tic = time.time() 
    builtin_outputs = map(compute_something, inputs) 
    print 'Built-in:', time.time() - tic 

    tic = time.time() 
    pool_outputs = pool.map(compute_something, inputs) 
    print 'Pool :', time.time() - tic 

này chạy tốt, trở về

Pool size: 8 
Built-in: 1.56904006004 
Pool : 0.447728157043 

Nhưng nếu tôi bỏ ghi chú dòng import scipy.special, tôi nhận được:

Pool size: 8 
Built-in: 1.58968091011 
Pool : 1.59387993813 

và tôi có thể thấy rằng chỉ có một lõi đang thực hiện công việc trên hệ thống của tôi. Trong thực tế, nhập khẩu bất kỳ mô-đun từ gói scipy dường như có hiệu ứng này (tôi đã thử một số).

Bất kỳ ý tưởng nào? Tôi chưa bao giờ nhìn thấy một trường hợp như thế này trước đây, nơi mà một sự nhập khẩu rõ ràng vô hại có thể có một hiệu ứng kỳ lạ và bất ngờ.

Cảm ơn!

Cập nhật (1)

Di chuyển các dòng nhập khẩu scipy đến chức năng compute_something phần cải thiện các vấn đề:

Pool size: 8 
Built-in: 1.66807389259 
Pool : 0.596321105957 

Update (2)

Nhờ @larsmans cho thử nghiệm trên một hệ thống khác. Sự cố không được xác nhận bằng Scipy v.0.12.0. Di chuyển truy vấn này vào danh sách gửi thư scipy và sẽ đăng bất kỳ câu trả lời nào.

+0

Không thể sao chép bằng Python 2.7.5, SciPy 0.12.0. Phiên bản bạn đang sử dụng? –

+0

Thú vị, cảm ơn bạn đã thử! Tôi đang sử dụng 0.14.0b1. Tôi cần một số mô-đun gần đây hơn, do đó sử dụng một phiên bản mới hơn. – Gabriel

+0

Tôi khuyên bạn nên thử phiên bản ổn định - và nếu điều đó khắc phục được sự cố, hãy thử liên hệ với danh sách gửi thư của SciPy. Gỡ lỗi phiên bản beta của thư viện không thực sự là thứ SO. –

Trả lời

7

Sau nhiều lần đào bới và posting an issue trên trang web Scipy GitHub, tôi đã tìm thấy giải pháp.

Trước khi bắt đầu, đây là tài liệu rất tốt here - Tôi sẽ chỉ cung cấp tổng quan.

Sự cố này là không liên quan đến phiên bản Scipy hoặc Numpy mà tôi đang sử dụng. Nó bắt nguồn từ thư viện BLAS hệ thống mà Numpy và Scipy sử dụng cho các thói quen đại số tuyến tính khác nhau. Bạn có thể nói mà thư viện NumPy được liên kết với bằng cách chạy

python -c 'import numpy; numpy.show_config()'

Nếu bạn đang sử dụng OpenBLAS trong Linux, bạn có thể thấy rằng các mối quan hệ CPU được thiết lập để 1, có nghĩa rằng một khi các thuật toán được nhập khẩu bằng Python (thông qua Numpy/Scipy), bạn có thể truy cập tối đa một lõi của CPU. Để kiểm tra điều này, trong một thiết bị đầu cuối chạy Python

import os 
os.system('taskset -p %s' %os.getpid()) 

Nếu mối quan hệ CPU được trả về như f, của ff, bạn có thể truy cập nhiều lõi. Trong trường hợp của tôi nó sẽ bắt đầu như thế, nhưng khi nhập khẩu sumpy hoặc scipy.any_module, nó sẽ chuyển sang 1, do đó vấn đề của tôi.

Tôi đã tìm thấy hai giải pháp:

Thay đổi CPU ái lực

Bạn có thể tự thiết lập các mối quan hệ CPU của quá trình tổng thể ở phía trên cùng của hàm main để mã trông như thế này:

import multiprocessing 
import numpy as np 
import math 
import time 
import os 

def compute_something(t): 
    a = 0. 
    for i in range(10000000): 
     a = math.sqrt(t) 
    return a 

if __name__ == '__main__': 

    pool_size = multiprocessing.cpu_count() 
    os.system('taskset -cp 0-%d %s' % (pool_size, os.getpid())) 

    print "Pool size:", pool_size 
    pool = multiprocessing.Pool(processes=pool_size) 

    inputs = range(10) 

    tic = time.time() 
    builtin_outputs = map(compute_something, inputs) 
    print 'Built-in:', time.time() - tic 

    tic = time.time() 
    pool_outputs = pool.map(compute_something, inputs) 
    print 'Pool :', time.time() - tic 

Lưu ý rằng lựa chọn một giá trị cao hơn so với số lượng lõi cho taskset dường như không quan trọng - nó chỉ sử dụng số lượng tối đa có thể.

Chuyển BLAS thư viện

Giải pháp ghi nhận tại site liên kết ở trên. Về cơ bản: cài đặt libatlas và chạy update-alternatives để trỏ tới ATLAS chứ không phải OpenBLAS.