I wrote a pythonic server with socket. that should receives requests at the same time(parallel) and respond them parallel. When i send more than one request to it, the time of answering increase more than i expected.
server:
import datetime
import asyncio, timeit
import json, traceback
from asyncio import get_event_loop
requestslist = []
loop = asyncio.get_event_loop()
async def handleData(reader, writer):
message = ''
clientip = ''
data = bytearray()
print("Async HandleData", datetime.datetime.utcnow())
try:
start = timeit.default_timer()
data = await reader.readuntil(separator=b'\r\n\r\n')
msg = data.decode(encoding='utf-8')
len_csharp_message = int(msg[msg.find('content-length:') + 15:msg.find(';dmnid'):])
data = await reader.read(len_csharp_message)
message = data.decode(encoding='utf-8')
clientip = reader._transport._extra['peername'][0]
clientport = reader._transport._extra['peername'][1]
print('\nData Received from:', clientip, ':', clientport)
if (clientip, message) in requestslist:
reader._transport._sock.close()
else:
requestslist.append((clientip, message))
# adapter_result = parallel_members(message_dict, service, dmnid)
adapter_result = '''[{"name": {"data": "data", "type": "str"}}]'''
body = json.dumps(adapter_result, ensure_ascii=False)
print(body)
contentlen = len(bytes(str(body), 'utf-8'))
header = bytes('Content-Length:{}'.format(contentlen), 'utf-8')
result = header + bytes('\r\n\r\n{', 'utf-8') + body + bytes('}', 'utf-8')
stop = timeit.default_timer()
print('total_time:', stop - start)
writer.write(result)
writer.close()
writer.close()
# del writer
except Exception as ex:
writer.close()
print(traceback.format_exc())
finally:
try:
requestslist.remove((clientip, message))
except:
pass
def main(*args):
print("ready")
loop = get_event_loop()
coro = asyncio.start_server(handleData, 'localhost', 4040, loop=loop, limit=204800000)
srv = loop.run_until_complete(coro)
loop.run_forever()
if __name__ == '__main__':
main()
When i send single request, it tooke 0.016 sec. but for more request, this time increase.
cpu info : intel xeon x5650
client:
import multiprocessing, subprocess
import time
from joblib import Parallel, delayed
def worker(file):
subprocess.Popen(file, shell=False)
def call_parallel (index):
print('begin ' , index)
p = multiprocessing.Process(target=worker(index))
p.start()
print('end ' , index)
path = r'python "/test-Client.py"' # ## client address
files = [path, path, path, path, path, path, path, path, path, path, path, path]
Parallel(n_jobs=-1, backend="threading")(delayed(call_parallel)(i) for index,i in enumerate(files))
for this client that send 12 requests synchronous, total time for per request is 0.15 sec.
I expect for any number requests, the time be fixed.
What is request
Single request (roughly saying) consists of the following steps:
№1/№3 processed by your CPU very fast. Step №2 - is a bytes journey from your PC to some server (in another city, for example) and back by wires: it usually takes much more time.
How asynchronous requests work
Asynchronous requests are not really "parallel" in terms of processing: it's still your single CPU core that can process one thing at a time. But running multiple async requests allows you to use step №2 of some request to do steps №1/№3 of other request instead of just wasting huge amount of time. That's a reason why multiple async requests usually would finish earlier then same amount of sync ones.
Running async code without network delay
But when you run things locally, step №2 doesn't take much time: your PC and server are the same thing and bytes don't go to network journey. There is just no time that can be used in step №2 to start new request. Only your single CPU core works processing one thing at a time.
You should test requests against server that answers with some delay to see results you expect.