Python的asyncore使用变量超时定期发送数据.有没有更好的办法?

Nic*_*eld 8 python sockets asynchronous

我想编写一个客户端可以连接到的服务器并接收定期更新而无需轮询.我遇到的asyncore问题是,如果在调用dispatcher.writable()时没有返回true,则必须等到asyncore.loop超时后(默认为30秒).

我试图解决这个问题的两种方法是:1)将超时减少到一个较低的值或2)查询连接,以便下次更新并生成足够的超时值.但是,如果你在'man 2 select_tut'中引用'Select Law',它会说,"你应该总是尝试使用select()而不会超时."

有一个更好的方法吗?可能扭曲?我想尝试避免额外的线程.我将在这里包含变量超时示例:

#!/usr/bin/python

import time
import socket
import asyncore


# in seconds
UPDATE_PERIOD = 4.0

class Channel(asyncore.dispatcher):

    def __init__(self, sock, sck_map):
        asyncore.dispatcher.__init__(self, sock=sock, map=sck_map)
        self.last_update = 0.0  # should update immediately
        self.send_buf = ''
        self.recv_buf = ''

    def writable(self):
        return len(self.send_buf) > 0

    def handle_write(self):
        nbytes = self.send(self.send_buf)
        self.send_buf = self.send_buf[nbytes:]

    def handle_read(self):
        print 'read'
        print 'recv:', self.recv(4096)

    def handle_close(self):
        print 'close'
        self.close()

    # added for variable timeout
    def update(self):
        if time.time() >= self.next_update():
            self.send_buf += 'hello %f\n'%(time.time())
            self.last_update = time.time()

    def next_update(self):
        return self.last_update + UPDATE_PERIOD


class Server(asyncore.dispatcher):

    def __init__(self, port, sck_map):
        asyncore.dispatcher.__init__(self, map=sck_map)
        self.port = port
        self.sck_map = sck_map
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind( ("", port))
        self.listen(16)
        print "listening on port", self.port

    def handle_accept(self):
        (conn, addr) = self.accept()
        Channel(sock=conn, sck_map=self.sck_map)

    # added for variable timeout
    def update(self):
        pass

    def next_update(self):
        return None


sck_map = {}

server = Server(9090, sck_map)
while True:
    next_update = time.time() + 30.0
    for c in sck_map.values():
        c.update()  # <-- fill write buffers
        n = c.next_update()
        #print 'n:',n
        if n is not None:
            next_update = min(next_update, n)
    _timeout = max(0.1, next_update - time.time())

    asyncore.loop(timeout=_timeout, count=1, map=sck_map)
Run Code Online (Sandbox Code Playgroud)

Mar*_*wis 4

“选择法”不适用于您的情况,因为您不仅有客户端触发的(纯服务器)活动,而且还有时间触发的活动 - 这正是选择超时的目的。法律真正应该说的是“如果你指定了超时,请确保在超时到来时你实际上必须做一些有用的事情”。法律旨在防止忙等待;你的代码不忙等待。

我不会将 _timeout 设置为最大值 0.1 和下一次更新时间,而是设置为最大值 0.0 和下一次超时。IOW,如果在您进行更新时更新期已过期,您应该立即执行该特定更新。

您可以将所有通道存储在优先级队列中(按下次更新时间排序),然后只对最早的通道运行更新(直到找到更新时间未更新的通道),而不是每次都询问每个通道是否要更新。到达的)。您可以使用 heapq 模块来实现这一点。

您还可以通过不让每个通道询问当前时间而只轮询一次当前时间并将其传递给 .update 来节省一些系统调用。