Define writable method in asyncore client makes sending data very slow
Question: I wrote a asynchorous client using python asyncore, and met some problems. I
have solved this with the help of this:

[Asyncore client in thread makes the whole program crash when sending data
immediately](http://stackoverflow.com/questions/27399960/asyncore-client-in-
thread-makes-the-whole-program-crash-when-sending-data-immedi)

But now I meet some other problem.

My client program:

    
    
    import asyncore, threading, socket
    class Client(threading.Thread, asyncore.dispatcher):
        def __init__(self, host, port):
            threading.Thread.__init__(self)
            self.daemon = True
            self._thread_sockets = dict()
            asyncore.dispatcher.__init__(self, map=self._thread_sockets)
            self.host = host
            self.port = port
            self.output_buffer = []
            self.start()
    
        def send(self, msg):
            self.output_buffer.append(msg)
        def writable(self):
            return len("".join(self.output_buffer)) > 0
        def handle_write(self):
            all_data = "".join(self.output_buffer)
            bytes_sent = self.socket.send(all_data)
            remaining_data = all_data[bytes_sent:]
            self.output_buffer = [remaining_data]
        def handle_close(self):
            self.close()
        def handle_error(self):
            print("error")
        def handle_read(self):
            print(self.recv(10))
        def run(self):
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.connect((self.host, self.port))
            asyncore.loop(map = self._thread_sockets)
    
    mysocket = Client("127.0.0.1",8400)
    while True:
        a=str(input("input"))
        mysocket.send("popo")
    

And my server program:

    
    
    import socket
    HOST="127.0.0.1"
    PORT=8400
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print("socket created")
    s.bind((HOST, PORT))
    s.listen(1)
    print("listen")
    conn,addr = s.accept()
    print("Accepted. Receiving")
    while True:
        data = conn.recv(20)
        print("Received: ")
        print(data)
        data = input("Please input reply message:\n").encode("utf-8")
        conn.send(data)
        print("Data sended. Receiving")
    

My problem is sending data from client to server is very slow, about 20 to 30
seconds! But it could always send data successfully. And if I comment out the
writable method in client, the sending process becomes very fast. Why does it
behave like this? How to fix it if I want to use the writable method? Thanks!

I start the server with python3, and client with python 2. I use ubuntu 14.04.


Answer: The `asyncore` loop calls `writable()` when it is ready to do something with
the socket. If the method `writable()` tells that there is something to write
then `handle_write()` is called. The default `writable()` always returns
`True`, so in that case there is busy loop calling `handle_write()` and
`writable()`.

In the above implementation the method `writable()` is called immediately when
the client loop is started. At that moment there is nothing in the buffer, so
`writable()` tells that there is nothing to write.

The `asyncore` loop calls `select()`. Now the loop is in "standby" state. It
can be wakened only when some data is received by the socket or by timeout
event. After any of those events the loop again checks `writable()`.

The server sends nothing to the client and the client waits for timeout. The
default `timeout` is 30 seconds, so that is why it is needed to wait up to 30
seconds before something is sent. It is possible to reduce the timeout during
starting `asyncore.loop()`:

    
    
        asyncore.loop(map = self._thread_sockets, timeout = 0.5)
    

* * *

Another idea that may come here is to check if the buffer is empty in `send()`
and if it is empty send it immediately. However, it is a bad idea. The
`send()` is called in the main thread, but the socket is managed by the
`asyncore` loop in another thread.

For the same reason it makes sense to protect usage of `output_buffer` for
concurrent access from different threads. The lock object `threading.Lock()`
can be used here:

    
    
    def __init__(self, host, port):
        #...
        self.lock = threading.Lock()
    
    def send(self, msg):
        self.lock.acquire()
        try:
            self.output_buffer.append(msg)
        finally:
            self.lock.release()
    
    def writable(self):
        is_writable = False;
        self.lock.acquire()
        try:
            is_writable = len("".join(self.output_buffer)) > 0
        finally:
            self.lock.release()
    
        return is_writable
    
    def handle_write(self):
        self.lock.acquire()
        try:
            all_data = "".join(self.output_buffer)
            bytes_sent = self.socket.send(all_data)
            remaining_data = all_data[bytes_sent:]
            self.output_buffer = [remaining_data]
        finally:
            self.lock.release()
    

There is no thread safe mechanism to waken `asyncore` from another thread. So,
the only solution is to reduce loop timeout, although too small timeout
increases CPU usage.

