High performance IO on non-blocking sockets

Troels Walsted Hansen troels at thule.no
Sat Mar 15 06:33:57 EST 2003


Jp Calderone wrote:
>>  send_buffer = buffer(self.data, self.offset)
>>  sent = self.socket.send(send_buffer)
>>  self.buffer_offset += sent
>   Have you timed this, vs the original, naive code?  

I have to admit that I haven't timed it. I've only looked at the Python 
source and based my statements on that.

 > Slicing a string
> shouldn't copy any bytes, only create a new string object with a modified
> starting pointer and length.  

I believe this is wrong, at least for Python 2.2.2 which I'm working 
with. Only if the string slice is the same as the original string do you 
get an optimized slice without any copying. See source snippet below.

The buffer object is the one that implements read-only slices in the 
manner that you describe.

static PyObject *
string_slice(register PyStringObject *a, register int i, register int j)
{
         [...]
         if (i == 0 && j == a->ob_size && PyString_CheckExact(a)) {
                 /* It's the same as a */
                 Py_INCREF(a);
                 return (PyObject *)a;
         }
         [...]
         return PyString_FromStringAndSize(a->ob_sval + i, (int) (j-i));

 > This seems as if it would be about as
> expensive as creating a new buffer object, but has the advantage of running
> more of the work in C, rather than Python (no name lookup for buffer, for
> example).
> 
>   I ask because I can't seem to squeeze any speedup out of Twisted by making
> this change (in fact, I find a significant slowdown, 12309.8 KB/s using the
> original "buf = buf[sent:]" code to 9408.2 KB/s using the buffer()
> approach).
> 
>   I'm hoping I've just screwed something up, of course, and would love to
> hear that the buffer() approach is, in fact, much faster :)

Your numbers are surprising and very interesting. Would you care to test 
a modified send loop with the Twisted framework for me?

   if self.offset:
       sent = self.socket.send(buffer(self.data, self.offset))
   else:
       sent = self.socket.send(self.data)
   self.offset += sent

The idea here is to avoid the cost of creating a buffer object for short 
sends that fit into the kernel's socket buffer.

How large is self.data in your test?

-- 
Troels Walsted Hansen





More information about the Python-list mailing list