2010-07-21 25 views
6

Có kinh nghiệm 1 ngày ở Twisted tôi cố gắng lên lịch gửi tin nhắn trả lời tcp client:Python bị xoắn: cách lên lịch?

import os, sys, time 
from twisted.internet import protocol, reactor 

self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
for timeout, data in self.scenario: 
     reactor.callLater(timeout, self.sendata, data) 
     print "waited %d time, sent %s\n"%(timeout, data) 

Bây giờ nó sẽ gửi thông điệp, nhưng tôi có 2 vấn đề:
1) "timeout" đang diễn ra từ " bây giờ ", và tôi muốn đếm nó sau mỗi nhiệm vụ trước đã được hoàn thành (tin nhắn trước đó đã được gửi)
2) Tôi không biết cách đóng kết nối sau khi tất cả các tin nhắn được gửi đi. Nếu tôi đặt self.transport.loseConnection() sau callLater giây nó sẽ đóng kết nối ngay lập tức.

Trong lần thử trước, tôi không sử dụng reactor.callLater, nhưng chỉ self.transport.write()time.sleep(n) trong vòng for. Trong trường hợp này, tất cả các tin nhắn được gửi cùng nhau sau khi hết thời gian chờ ... Không phải thứ tôi muốn.
Mục đích là chờ kết nối máy khách, chờ timeout1 và gửi tin nhắn1, chờ timeout2 và gửi tin nhắn2, ... vv Sau khi thông báo cuối cùng - kết nối đóng.

Trả lời

8

Điều quan trọng cần nhận ra khi làm việc với Twisted là không có gì chờ đợi bất cứ điều gì. Khi bạn gọi reactor.callLater(), bạn đang yêu cầu lò phản ứng gọi một số thứ sau, không phải bây giờ. Cuộc gọi kết thúc ngay lập tức (sau khi cuộc gọi đã được lên lịch, trước khi nó đã được thực thi.) Do đó, tuyên bố print của bạn là một lời nói dối: bạn không đợi thời gian timeout; bạn đã không chờ chút nào.

Bạn có thể sửa lỗi theo nhiều cách và sử dụng tùy thuộc vào những gì bạn thực sự muốn. Nếu bạn muốn nhiệm vụ thứ hai bắt đầu bốn giây sau khi nhiệm vụ đầu tiên bắt đầu, bạn có thể chỉ cần thêm độ trễ (biến số timeout) của tác vụ đầu tiên vào việc trì hoãn nhiệm vụ thứ hai. Nhiệm vụ đầu tiên có thể không bắt đầu chính xác khi bạn lên lịch, mặc dù vậy; nó có thể bắt đầu sau đó, nếu Twisted là quá bận rộn để bắt đầu nó sớm hơn. Ngoài ra, nếu nhiệm vụ của bạn mất một thời gian dài nó có thể không thực sự được thực hiện trước khi nhiệm vụ thứ hai bắt đầu.

Cách phổ biến hơn là cho nhiệm vụ đầu tiên lên lịch tác vụ thứ hai, thay vì lập lịch công việc thứ hai ngay lập tức. Bạn có thể lên lịch bốn giây sau khi nhiệm vụ đầu tiên kết thúc (bằng cách gọi reactor.callLater() ở cuối nhiệm vụ đầu tiên), hoặc bốn giây sau khi nhiệm vụ đầu tiên bắt đầu (bằng cách gọi reactor.callLater() tại số bắt đầu của tác vụ đầu tiên) hoặc thực hiện thêm tính toán phức tạp để xác định thời điểm bắt đầu, theo dõi thời gian trôi qua.

Khi bạn nhận ra không có gì trong Twisted waits, xử lý việc đóng kết nối khi bạn thực hiện tất cả các tác vụ đã lên lịch trở nên dễ dàng: bạn chỉ cần thực hiện cuộc gọi công việc cuối cùng self.transport.loseConnection(). Đối với các tình huống phức tạp hơn, bạn có thể muốn chuỗi Deferred s với nhau hoặc sử dụng DeferredList để thực hiện loseConnection() khi tất cả các tác vụ đang chờ xử lý kết thúc, ngay cả khi chúng không hoàn toàn tuần tự.

+0

Cảm ơn, bây giờ tôi hiểu tại sao "ngủ" đã không làm việc. Bạn có thể đưa ra một ví dụ với lịch trình reactor.callLater() ở cuối của reactor.callLater trước đó()? – DominiCane

+0

Chỉ cần định nghĩa một hàm gọi là 'self.sendata (dữ liệu)' và sau đó gọi 'reactor.callLater()' cho lần gọi lại tiếp theo, và chuyển hàm đó cho 'reactor.callLater()' đầu tiên thay vì 'self.sendata ' –

4

giải pháp cuối cùng cho thỏa thuận này ..

import os, sys, time 
from twisted.internet import protocol, reactor 
import itertools 

def sendScenario(self): 
    def sendelayed(d): 
     self.sendata(d) 
     self.factory.out_dump.write(d) 
     try: 
      timeout, data = next(self.sc) 
      reactor.callLater(timeout, sendelayed, data) 
     except StopIteration: 
      print "Scenario completed!" 
      self.transport.loseConnection() 

    self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
    self.sc = iter(self.scenario) 
    timeout, data = next(self.sc) 
    reactor.callLater(timeout, sendelayed, data) 
+0

Chỉ cần fyi:' self.scenario .__ iter __() '->' iter (self.scenario) ',' self.sc.next() '->' next (self.sc) '(kể từ 2.6 tôi nghĩ) –

+0

Cảm ơn, đã thay đổi nó. – DominiCane

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