2010-06-25 30 views
5

Tôi đã quyết định tìm hiểu cách đa luồng được thực hiện bằng Python, và tôi đã so sánh để xem loại hiệu năng nào tôi có được trên CPU lõi kép. Tôi thấy rằng mã đa luồng đơn giản của tôi thực sự chạy chậm hơn so với tuần tự tương đương, và tôi không thể hiểu tại sao.Threading Python bất ngờ chậm hơn

Các thử nghiệm tôi contrived là để tạo ra một danh sách lớn các số ngẫu nhiên và sau đó in tối đa

from random import random 
import threading 

def ox(): 
    print max([random() for x in xrange(20000000)]) 

ox() mất khoảng 6 giây để hoàn thành trên của tôi Intel Core 2 Duo, trong khi ox();ox() mất khoảng 12 giây.

Sau đó tôi đã thử gọi hàm ox() từ hai luồng để xem tốc độ hoàn thành nhanh như thế nào.

def go(): 
    r = threading.Thread(target=ox) 
    r.start() 
    ox() 

go() mất khoảng 18 giây để hoàn thành, với hai kết quả được in trong vòng 1 giây. Tại sao điều này nên chậm hơn?

Tôi nghi ngờ ox() đang được tự động song song, vì tôi xem tab hiệu suất của trình quản lý tác vụ Windows và gọi ox() trong bảng điều khiển python của tôi, cả hai bộ xử lý sẽ chuyển sang sử dụng 75% cho đến khi hoàn thành. Liệu Python có tự động song song những thứ như max() khi nó có thể?

Trả lời

9
  1. Python có GIL. Mã byte bytecode sẽ chỉ được thực hiện bởi một bộ xử lý duy nhất tại một thời điểm. Chỉ một số mô-đun C (không quản lý trạng thái Python) sẽ có thể chạy đồng thời.
  2. Python GIL có chi phí rất lớn trong việc khóa trạng thái giữa các luồng. Có các bản sửa lỗi cho điều này trong các phiên bản mới hơn hoặc trong các nhánh phát triển - ít nhất là nên tạo mã ràng buộc CPU đa luồng nhanh như mã luồng đơn.

Bạn cần sử dụng khung công tác đa quy trình để song song với Python. May mắn thay, mô-đun multiprocessing đi kèm với Python khiến việc này trở nên dễ dàng.

Rất ít ngôn ngữ có thể tự động song song biểu thức. Nếu đó là chức năng bạn muốn, tôi đề nghị Haskell (Dữ liệu song song Haskell)

+5

Cần lưu ý rằng luồng vẫn hữu ích trong Python đối với một số loại nhiệm vụ nhất định, chẳng hạn như các hoạt động I/O-bound. –

1

Sự cố ở chức năng ngẫu nhiên() Nếu bạn xóa ngẫu nhiên khỏi mã của mình. Cả hai lõi đều cố gắng truy cập trạng thái chia sẻ của hàm ngẫu nhiên. Lõi làm việc liên tục và dành rất nhiều thời gian cho việc đồng bộ hóa bộ nhớ cache. Hành vi như vậy được gọi là chia sẻ sai. Đọc bài viết này False Sharing