2009-11-08 28 views
11

Tôi đang cố gắng sử dụng các đề tài trong một dự án Python mà tôi đang làm việc, nhưng các luồng có vẻ không hoạt động như chúng được cho là trong mã của tôi. Dường như tất cả các chuỗi chạy tuần tự (tức là thread2 bắt đầu sau khi chuỗi 1 kết thúc, chúng không bắt đầu cùng một lúc). Tôi đã viết một kịch bản đơn giản để kiểm tra điều này, và điều đó cũng chạy các chuỗi liên tục.Threading Python xuất hiện để chạy các chuỗi liên tiếp

import threading 

def something(): 
    for i in xrange(10): 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

Dưới đây là kết quả tôi nhận được từ chạy nó:

Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
Hello 
world 
world 
world 
world 
world 
world 
world 
world 
world 
world 

Các hành vi tương tự được quan sát với số lượng lớn hơn rất nhiều lần lặp của vòng lặp.

Tôi đã thử tìm kiếm trên web và các câu trả lời cũ hơn SO, nhưng tôi không thể tìm thấy bất kỳ điều gì hữu ích. Ai đó có thể vui lòng chỉ ra điều gì sai với mã này?

Trả lời

13

Hiện tại trong python, các luồng được thay đổi sau khi thực hiện một số lượng chỉ định bytecode cụ thể. Họ không chạy cùng một lúc. Bạn sẽ chỉ có các luồng thực hiện song song khi một trong số chúng gọi một số mô-đun I/O-chuyên sâu hoặc không ảnh hưởng đến python có thể giải phóng GIL (khóa thông dịch toàn cầu).

Tôi khá chắc chắn bạn sẽ nhận được kết quả đầu ra hỗn hợp nếu bạn làm tăng số vòng lặp tới một cái gì đó như 10000. Hãy nhớ rằng chỉ đơn giản là sinh ra chuỗi thứ hai cũng mất "rất nhiều" thời gian.

+0

Hành vi tương tự với 10000 lần lặp – MAK

+0

Trên dự án thực tế mà tôi đang làm việc, một trong các chuỗi là một vòng lặp vô hạn lắng nghe tin nhắn và gọi hàm gọi lại họ đến. Nó chỉ chặn tất cả các chủ đề khác. Thật không may, mã vòng lặp thực tế không thể sửa đổi được (tôi chỉ gọi phương thức run() của một lớp trong chuỗi). – MAK

+0

Khi tôi chạy tập lệnh như sau: './pythr.py | uniq -c' Tôi nhận được: 8969 Xin chào | 1 Xin chào thế giới | 6626 thế giới | 1 | Thế giới 3373 | 1030 Xin chào. Vì vậy, nó thay đổi điều khiển - chỉ cần không thường xuyên đó ... – viraptor

10

Trong thời gian cần chuỗi thứ hai để bắt đầu các vòng lặp và bản in đầu tiên đã có.

Ở đây có vẻ như thế này, bạn có thể thấy chuỗi thứ hai bắt đầu sau khi phát ra lần đầu tiên một vài hellos.

Hello 
Hello 
Hello 
Hello 
Hello 
Helloworld 

Helloworld 

Helloworld 

Helloworld 

Helloworld 

world 
world 
world 
world 
world 

Btw: Ví dụ của bạn không có ý nghĩa gì cả. Lý do duy nhất cho Threads là IO và IO chậm. Khi bạn thêm một số ngủ để mô phỏng IO nó cũng làm việc như mong đợi:

import threading 
from time import sleep 

def something(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "Hello" 

def my_thing(): 
    for i in xrange(10): 
     sleep(0.01) 
     print "world" 

threading.Thread(target=something).start() 
threading.Thread(target=my_thing).start() 

một hỗn hợp tự nhiên xuất hiện:

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

Helloworld 

worldHello 

Helloworld 

worldHello 

Helloworld 
+2

Tôi không nhận được kết quả như vậy ngay cả với số lượng lớn hơn/nhỏ hơn số lần lặp của vòng lặp. Trên máy tính của tôi, nó luôn luôn tuần tự. Tôi nghĩ rằng đây là hệ điều hành/xử lý phụ thuộc, như abyx đề nghị. – MAK

+0

Như tôi đã nói trong câu hỏi của tôi, đây chỉ là một ví dụ cho vấn đề của tôi, không phải là mã tôi đang làm việc với (đó là lớn hơn nhiều). Trong mã thực tế của tôi, một trong các luồng chạy một vòng lặp lắng nghe tín hiệu dbus. – MAK

3

Điều này thực sự phụ thuộc vào lịch trình Hệ điều hành của bạn, bộ vi xử lý của bạn.
Ngoài ra, nó được biết rằng chủ đề của CPython là không hoàn hảo vì GIL (PDF), trong ngắn hạn, có nghĩa là rất nhiều chủ đề lần chạy tuần tự, hoặc một cái gì đó của loại đó.

+2

Bạn có thể có nghĩa là các chủ đề CPython bị GIL ... Không có GIL trong, ví dụ, Jython. – EOL

+0

@EOL - bạn chính xác, tôi đã cập nhật câu trả lời – abyx

4

Hành vi cũng có thể thay đổi tùy theo hệ thống đang sử dụng có một bộ xử lý đơn hoặc nhiều bộ xử lý, như được giải thích bởi this talk bởi David Beazley.

Như viraptor nói, luồng đầu tiên sẽ giải phóng GIL sau khi thực thi bytec.getcheckinterval() bytecodes (100 theo mặc định). Để tóm tắt những gì David Beazley nói, trên một hệ thống xử lý đơn lẻ, luồng thứ hai sẽ có cơ hội tiếp quản. Tuy nhiên trên một hệ thống đa lõi luồng thứ hai có thể chạy trên một lõi khác, và luồng đầu tiên sẽ cố gắng phản hồi khóa và có thể sẽ thành công vì hệ điều hành sẽ không có thời gian để chuyển đổi bộ vi xử lý. Điều này có nghĩa là trên một hệ thống đa lõi với một chủ đề ràng buộc CPU mà các chủ đề khác có thể không bao giờ có được một cái nhìn.

Cách vòng này là thêm một lệnh ngủ vào cả hai vòng để chúng không còn nữa CPU bị ràng buộc.

Các vấn đề liên quan