2013-05-05 29 views
6

Câu hỏi này khiến tôi kéo tóc ra.Nhà phát triển Python biết ai đang gọi?

nếu tôi làm:

def mygen(): 
    for i in range(100): 
     yield i 

và gọi nó là từ một ngàn chủ đề, làm thế nào để tạo hiểu biết những gì để gửi tới cho mỗi thread? Mỗi khi tôi gọi nó, máy phát có lưu bảng với bộ đếm và thông tin người gọi hoặc một cái gì đó tương tự không?

Thật kỳ lạ.

Hãy làm rõ suy nghĩ của tôi về điều đó.

Trả lời

6

mygen không phải nhớ bất cứ điều gì. Mọi cuộc gọi đến mygen() đều trả về một lần lặp độc lập. Mặt khác, các vòng lặp này có trạng thái: Mỗi lần next() được gọi là một, nó nhảy tới đúng vị trí trong mã máy phát - khi gặp phải yield, điều khiển được trả lại cho người gọi. Việc thực hiện thực tế khá lộn xộn, nhưng về nguyên tắc bạn có thể tưởng tượng rằng một trình vòng lặp như vậy lưu trữ các biến cục bộ, bytecode và vị trí hiện tại trong bytecode (con trỏ lệnh a.k.a.). Không có gì đặc biệt về các chủ đề ở đây.

+0

Vâng, các chủ đề chỉ để minh họa vấn đề. Xem xét rằng máy phát điện có thể cung cấp cho cái nhìn sai lầm của concurrency (hoặc một cái gì đó đen hơn ma thuật hơn) để python người mới bắt đầu. –

+0

@PatrickBassut: Vâng, bạn có thể mô phỏng [coroutines] (https://en.wikipedia.org/wiki/Coroutine) với chúng, và với coroutines bạn có thể tạo [green threads] (https://en.wikipedia.org)/wiki/Green_threads). Máy phát điện – icktoofay

2

Một chức năng như thế này, khi được gọi, sẽ trả về một đối tượng máy phát điện. Nếu bạn có các chủ đề riêng biệt gọi next() trên cùng một đối tượng máy phát, chúng sẽ can thiệp vào nhau. Đó là để nói, 5 chủ đề gọi next() 10 lần mỗi sẽ nhận được 50 sản lượng khác nhau.

Nếu hai luồng mỗi tạo một trình tạo bằng cách gọi mygen() trong chuỗi, chúng sẽ có các đối tượng máy phát riêng biệt.

Máy phát điện là một đối tượng và trạng thái của nó sẽ được lưu trữ trong bộ nhớ, do đó, hai luồng mà mỗi tạo ra mygen() sẽ đề cập đến các đối tượng riêng biệt. Nó sẽ không khác với hai chủ đề tạo một đối tượng từ một class, chúng sẽ có một đối tượng khác nhau, mặc dù lớp này giống nhau.

nếu bạn đang ở đây từ nền C, đây là không giống với chức năng với biến số static. Trạng thái được duy trì trong một đối tượng, không tĩnh trong các biến chứa trong hàm.

+0

Bạn không trả lời được câu hỏi của mình. Tôi không muốn biết điều gì sẽ xảy ra, nhưng nó xảy ra như thế nào. Máy phát có giữ một số giá trị trong bộ nhớ khi một luồng tạo ra một bộ tạo không? –

+4

@PatrickBassut đối tượng máy phát điện có trạng thái giống như bất kỳ đối tượng nào khác, vì vậy có, trạng thái của nó sẽ được lưu trữ trong bộ nhớ. –

1

Có thể rõ ràng hơn nếu bạn nhìn theo cách này. Thay vì:

for i in mygen(): 
    . . . 

sử dụng:

gen_obj = mygen() 
for i in gen_obj: 
    . . . 

sau đó bạn có thể thấy rằng mygen() chỉ được gọi một lần, và nó tạo một đối tượng mới, và nó là đối tượng đó được lặp. Bạn có thể tạo hai chuỗi trong cùng một chuỗi, nếu bạn muốn:

gen1 = mygen() 
gen2 = mygen() 
print(gen1.__next__(), gen2.__next__(), gen1.__next__(), gen2.__next__()) 

Điều này sẽ in 0, 0, 1, 1.

Bạn có thể truy cập vào iterator tương tự từ hai chủ đề nếu bạn thích, chỉ cần lưu trữ các đối tượng phát trong một toàn cầu:

global_gen = mygen() 

Chủ đề 1:

for i in global_gen: 
    . . . 

Chủ đề 2:

for i in global_gen: 
    . . . 

Điều này có thể gây ra tất cả các loại tàn phá. :-)

+0

thật kỳ lạ. Bạn có thể gán chúng cho các biến, nhưng tại thời điểm bạn thực sự sử dụng chúng, nó bắt đầu tạo ra các giá trị theo kiểu "theo yêu cầu" nào đó. Nếu bạn chỉ định vị trí bộ nhớ của một hàm, điều đó hoàn toàn dễ hiểu. Nhưng theo như tôi biết, bạn không làm điều đó ở đó (bạn đang thực sự gọi hàm trong gen_obj = mygen()). Wow! –

+1

Khi bạn chuyển sang cấp độ tiếp theo của Python-Fu nghiêm trọng, bạn có thể chuyển con trỏ tới các phương thức __next __() bị ràng buộc như các cuộc gọi lại GUI. :-) –

+1

Hầu hết thời gian, câu lệnh "def" tạo một đối tượng hàm duy nhất từ ​​mã của bạn, được thực hiện khi bạn gọi hàm theo tên. Nếu mã có chứa "lợi nhuận", tuy nhiên, def tạo ra * hai * đối tượng chức năng: một trong đó được gọi là khi bạn gọi tên hàm không có mã của bạn cả; nó chỉ trả về đối tượng máy phát. Đối tượng hàm mà nó tạo ra từ mã của bạn được gọi thông qua thuộc tính __next__ của đối tượng máy phát đó và hàm đó giữ trạng thái của nó trong đối tượng bộ tạo và biết cách lưu và khôi phục nó giữa các cuộc gọi. –