Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Socket Performance

27 views
Skip to first unread message

sle...@gmail.com

unread,
Mar 13, 2008, 12:46:31 AM3/13/08
to
Can anyone explain why socket performance (throughput) varies
depending on the amount of data send and recv are called with?

For example: try creating a local client/server (running on the same
computer) where the server sends the client a fixed amount of data.
Using method A, recv(8192) and sendall( ) with 8192 bytes worth of
data. Do this 100 times. Using method B, recv(1) and sendall( ) with 1
byte worth of data. Do this 819200 times.

If you time both methods, method A has much greater throughput than
method B.

Server:

import socket
import random
import string
import time

HOST = 'localhost'
PORT = 50023
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr

string_1 = 'A'
string_8192 = ''.join([random.choice(string.letters + string.digits)
for i in range(8192)])

conn.sendall('Start')

start = time.clock()
total_data = 0
for i in range(0,100):
conn.sendall(string_8192)
total_data += len(string_8192)
print 'Send Speed (Long String): ' + str( total_data / (time.clock() -
start) / 1024 / 1024 ) + ' MB/sec\n\n'

start = time.clock()
total_data = 0
for i in range(0,819200):
conn.sendall(string_1)
total_data += len(string_1)
print 'Send Speed (Short String): ' + str( total_data / (time.clock()
- start) / 1024 / 1024 ) + ' MB/sec'

conn.close()


Client:

import socket
import time

HOST = 'localhost' # The remote host
PORT = 50023 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, 50026))
s.connect((HOST, PORT))

data = s.recv(5)
print 'From Server: ' + data

start = time.clock()
total_data = 0
while total_data < 819200:
data = s.recv(8192)
total_data += len(data)
print 'Receive Speed (Long String): ' + str( total_data /
(time.clock() - start) / 1024 / 1024 ) + ' MB/sec\n\n'

start = time.clock()
total_data = 0
while total_data < 819200:
data = s.recv(1)
total_data += len(data)
print 'Receive Speed (Short String): ' + str( total_data /
(time.clock() - start) / 1024 / 1024 ) + ' MB/sec'
s.close()

Brian Smith

unread,
Mar 13, 2008, 9:33:47 AM3/13/08
to pytho...@python.org
sle...@gmail.com wrote:
> Sent: Wednesday, March 12, 2008 9:47 PM
> To: pytho...@python.org
> Subject: Socket Performance

>
> Can anyone explain why socket performance (throughput) varies
> depending on the amount of data send and recv are called with?
>
> For example: try creating a local client/server (running on the same
> computer) where the server sends the client a fixed amount of data.
> Using method A, recv(8192) and sendall( ) with 8192 bytes
> worth of data. Do this 100 times. Using method B, recv(1) and
> sendall( ) with 1 byte worth of data. Do this 819200 times.
>
> If you time both methods, method A has much greater
> throughput than method B.

Why is it faster to drink a liter of water a cupful at a time than to
drink it out of an eyedropper?

- Brian

sle...@gmail.com

unread,
Mar 13, 2008, 1:18:44 PM3/13/08
to
On Mar 13, 9:33 am, "Brian Smith" <br...@briansmith.org> wrote:
> sle...@gmail.com wrote:
> > Sent: Wednesday, March 12, 2008 9:47 PM
> > To: python-l...@python.org

Well, lets say you have a situation where you're going to be
alternating between sending large and small chunks of data. Is the
solution to create a NetworkBuffer class and only call send when the
buffer is full, always recv(8192)?

Grant Edwards

unread,
Mar 13, 2008, 2:38:26 PM3/13/08
to
On 2008-03-13, sle...@gmail.com <sle...@gmail.com> wrote:

>> > For example: try creating a local client/server (running on the same
>> > computer) where the server sends the client a fixed amount of data.
>> > Using method A, recv(8192) and sendall( ) with 8192 bytes
>> > worth of data. Do this 100 times. Using method B, recv(1) and
>> > sendall( ) with 1 byte worth of data. Do this 819200 times.
>>
>> > If you time both methods, method A has much greater
>> > throughput than method B.
>>
>> Why is it faster to drink a liter of water a cupful at a time than to
>> drink it out of an eyedropper?

> Well, lets say you have a situation where you're going to be


> alternating between sending large and small chunks of data. Is the
> solution to create a NetworkBuffer class and only call send when the
> buffer is full, always recv(8192)?

If you need to send large and small chumks of data, the
solution is to send large and small chunks of data.

--
Grant

Message has been deleted

casti...@gmail.com

unread,
Mar 14, 2008, 3:02:06 AM3/14/08
to
> > Well, lets say you have a situation where you're going to be
> > alternating between sending large and small chunks of data. Is the
> > solution to create a NetworkBuffer class and only call send when the
> > buffer is full, always recv(8192)?
>
>         Or create a protocol where the first 16 bits (in network byte order)
> contain a length value for the subsequent data, and use a receive
> process that consists of:
>
> leng = ntoh(socket.recv(2))
> data = socket.receive(leng)
>
> (the send can combine the length with the data into a single packet)

Are two 'sends' guaranteed to arrive as at least two 'receives'?

Send-3: xxx
Send-3: yyy
Receive-6: xxxyyy

Bryan Olson

unread,
Mar 14, 2008, 3:42:05 AM3/14/08
to
casti...@gmail.com wrote:
[Dennis Lee Bieber had written:]

>> Or create a protocol where the first 16 bits (in network byte order)
>> contain a length value for the subsequent data, and use a receive
>> process that consists of:
>>
>> leng = ntoh(socket.recv(2))
>> data = socket.receive(leng)
>>
>> (the send can combine the length with the data into a single packet)
>
> Are two 'sends' guaranteed to arrive as at least two 'receives'?

No. Nor are they guaranteed to arrive as at least most two.

> Send-3: xxx
> Send-3: yyy
> Receive-6: xxxyyy

Can happen, though I think the problem with Dennis's code is the
other way. The recv in

leng = ntoh(socket.recv(2))

might return one byte of data, not two. The latter recv is similar.


--
--Bryan

Bryan Olson

unread,
Mar 14, 2008, 4:07:09 AM3/14/08
to
sle...@gmail.com wrote:
> Well, lets say you have a situation where you're going to be
> alternating between sending large and small chunks of data. Is the
> solution to create a NetworkBuffer class and only call send when the
> buffer is full, always recv(8192)?

Buffering can often improve performance, but with the above we'd
to too quick to prematurely jump to an as yet unwarranted conclusion.

You measured the one-large and many-small cases, but not the case
you actually have. You might be able to take various measurements
and generally characterize speed as a function of the number of
calls and the size of the send. I wouldn't be surprised if the
result is well approximated by a time per call plus a time per
byte.

In optimization, guessing is bad. Where you cannot reason with
mathematical rigor, measure. Where you can derive a purely
analytic result, taking the occasional measurements still isn't a
bad idea (but don't tell my algorithms students).

--
--Bryan

Message has been deleted

Gabriel Genellina

unread,
Mar 15, 2008, 4:33:30 AM3/15/08
to pytho...@python.org
En Thu, 13 Mar 2008 15:18:44 -0200, <sle...@gmail.com> escribió:

> Well, lets say you have a situation where you're going to be
> alternating between sending large and small chunks of data. Is the
> solution to create a NetworkBuffer class and only call send when the
> buffer is full, always recv(8192)?

No need to reinvent the wheel. socket objects already have a makefile
method returning a file-like object, which behaves like a buffered socket.

--
Gabriel Genellina

casti...@gmail.com

unread,
Mar 15, 2008, 5:00:44 AM3/15/08
to
On Mar 15, 3:33 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:

Newbie question: Can you write to the 'file-like object' a pickle,
and receive it intact-- as one string with nothing else?

I want to know because I want to send two pickles.

Bryan Olson

unread,
Mar 15, 2008, 9:18:01 AM3/15/08
to
casti...@gmail.com wrote:

> Gabriel Genellina wrote:
>> No need to reinvent the wheel. socket objects already have a makefile
>> method returning a file-like object, which behaves like a buffered socket.

That wheel is far from round, and needs some reinvention. Python's
file-like objects do not play nice with lower level calls, which
would be tolerable if they supported some well-defiend high-level
asynchronous I/O, but they do not.

> Newbie question: Can you write to the 'file-like object' a pickle,
> and receive it intact-- as one string with nothing else?

Yes, but there's a world of gotcha's. Sockets do not recognize
record boundaries, and Python's 'pickle' has holes one's enemies
could drive a truck through. Still, you can pickle, write, read,
un-pickle, and get back your data intact.

> I want to know because I want to send two pickles.

"Two pickles" sounds like a tasty snack, but also suggests you may
be playing hopscotch in a minefield. This is a helpful group. Give
us more to go on, and you are likely to receive thousands of
dollars worth of consulting for free.


--
--Bryan

casti...@gmail.com

unread,
Mar 15, 2008, 6:08:05 PM3/15/08
to
On Mar 15, 8:18 am, Bryan Olson <fakeaddr...@nowhere.org> wrote:

It depends on the situation. How generally applicable is this:

fun ListenerGeneric( port, factory, arrivedfun ):

which calls 'factory' on socketA.accept (and loops again), then
arrivedfun( stringA ) on message complete detection. ?. It should
start itself in a separate thread.

Or is this any better:

for x in connections():
startnewthreadwith x:
for y in messages( x ):
arrivedfun( y )

Gabriel Genellina

unread,
Mar 16, 2008, 2:29:10 PM3/16/08
to pytho...@python.org
En Sat, 15 Mar 2008 20:08:05 -0200, <casti...@gmail.com> escribi�:

This looks like a SocketServer + ThreadingMixIn + a RequestHandler (your
factory).
But as B. Olson already pointed, pickles are unsafe. Worse, it's not that
someone could send a specially crafted pickle that could execute some
arbitrary code: you're blindy executing whatever you receive!
xmlrpc may be a good alternative in some cases.

--
Gabriel Genellina

casti...@gmail.com

unread,
Mar 16, 2008, 7:55:44 PM3/16/08
to
On Mar 16, 1:29 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
> En Sat, 15 Mar 2008 20:08:05 -0200, <castiro...@gmail.com> escribi�:

I see. Just transmit a binary and execute that. Make sure to have
handles to your program publicly accessible too. I execute this.

0 new messages