I want to connect to a list of a lot of different sites very fast. Im using asyncio to do this in an asynchronous manner and now want to add a timeout for when connections should be ignored if they take too long to respond.
How do I implement this?
import ssl
import asyncio
from contextlib import suppress
from concurrent.futures import ThreadPoolExecutor
import time
@asyncio.coroutine
def run():
while True:
host = yield from q.get()
if not host:
break
with suppress(ssl.CertificateError):
reader, writer = yield from asyncio.open_connection(host[1], 443, ssl=True) #timout option?
reader.close()
writer.close()
@asyncio.coroutine
def load_q():
# only 3 entries for debugging reasons
for host in [[1, 'python.org'], [2, 'qq.com'], [3, 'google.com']]:
yield from q.put(host)
for _ in range(NUM):
q.put(None)
if __name__ == "__main__":
NUM = 1000
q = asyncio.Queue()
loop = asyncio.get_event_loop()
loop.set_default_executor(ThreadPoolExecutor(NUM))
start = time.time()
coros = [asyncio.async(run()) for i in range(NUM)]
loop.run_until_complete(load_q())
loop.run_until_complete(asyncio.wait(coros))
end = time.time()
print(end-start)
(On a sidenote: Has somebody an idea how to optimize this?)
Asyncio stands for asynchronous input output and refers to a programming paradigm which achieves high concurrency using a single thread or event loop.
Using the . run_in_executor() method of an event loop will provide the necessary interoperability between the two future types by wrapping the concurrent. futures. Future type in a call to asyncio.
asyncio is a library to write concurrent code using the async/await syntax. asyncio is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc.
Actually, asyncio is much slower due to the high impact of using coroutines. I have no numbers, so this is just a comment, instead of a post, but you can verify this with a simple http echo server written in both styles. Python + high performance async IO do not work together, sadly.
You can wrap the call to open_connection in asyncio.wait_for, which allows you to specify a timeout:
with suppress(ssl.CertificateError):
fut = asyncio.open_connection(host[1], 443, ssl=True)
try:
# Wait for 3 seconds, then raise TimeoutError
reader, writer = yield from asyncio.wait_for(fut, timeout=3)
except asyncio.TimeoutError:
print("Timeout, skipping {}".format(host[1]))
continue
Note that when TimeoutError is raised, the open_connection coroutine is also cancelled. If you don't want it to be cancelled (though I think you do want it to be cancelled in this case), you have wrap the call in asyncio.shield.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With