From 762804fb70b624bb394353124c12494972bf33f9 Mon Sep 17 00:00:00 2001 From: androiddrew Date: Fri, 6 Apr 2018 10:00:48 -0400 Subject: [PATCH] initial commit --- .gitignore | 70 +++++++++++++++++++++++++++++++++++++++++++ app.py | 37 +++++++++++++++++++++++ async_spinner.py | 42 ++++++++++++++++++++++++++ coroutine_chaining.py | 32 ++++++++++++++++++++ hello_coroutine.py | 24 +++++++++++++++ sleep_gather.py | 21 +++++++++++++ sync_socket.py | 20 +++++++++++++ 7 files changed, 246 insertions(+) create mode 100644 .gitignore create mode 100644 app.py create mode 100644 async_spinner.py create mode 100644 coroutine_chaining.py create mode 100644 hello_coroutine.py create mode 100644 sleep_gather.py create mode 100644 sync_socket.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..00f0784 --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +# virtualenv +env +venv + +# Pycharm +.idea + +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +pypyenv/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# Redis +/dump.rdb + +# Project +config.py \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..e21b6d7 --- /dev/null +++ b/app.py @@ -0,0 +1,37 @@ +import asyncio + + +async def find_divisibles(inrange, div_by): + """Really this is a bulk task""" + print("finding nums in range {} divisible by {}".format(inrange, div_by)) + located = [] + for i in range(inrange): + if i % div_by == 0: + located.append(i) + if i % 50000 == 0: + await asyncio.sleep(0.001) + + + print("Done w/ nums in range {} divisble by {}".format(inrange, div_by)) + return located + + +async def main(): + divs1 = loop.create_task(find_divisibles(50800000, 34113)) + divs2 = loop.create_task(find_divisibles(100052, 3210)) + divs3 = loop.create_task(find_divisibles(500, 3)) + await asyncio.wait([divs1, divs2, divs3]) + return divs1, divs2, divs3 + +if __name__ == '__main__': + try: + loop = asyncio.get_event_loop() + # returns a Task object, not the result objects themselves. You have to access the Task result + # to see the output + d1, d2, d3 = loop.run_until_complete(main()) + print(type(d1)) + print(d1.result()) + except Exception as e: + pass + finally: + loop.close() diff --git a/async_spinner.py b/async_spinner.py new file mode 100644 index 0000000..12fcbc3 --- /dev/null +++ b/async_spinner.py @@ -0,0 +1,42 @@ +import asyncio +import itertools +import sys + + +async def spin(msg): + write, flush = sys.stdout.write, sys.stdout.flush + for char in itertools.cycle('|/-\\'): + status = f"{char} {msg}" + write(status) + flush() + write('\x08' * len(status)) # backspace out the line + try: + await asyncio.sleep(.1) + except asyncio.CancelledError: + break + write(' ' * len(status) + '\x08' * len(status)) + + +async def slow_function(): + await asyncio.sleep(3) + return 42 + + +async def supervisor(): + spinner = loop.create_task(spin('Thinking!')) + print('Spinner Object:', spinner) + result = await slow_function() + spinner.cancel() + return result + + +if __name__ == '__main__': + try: + loop = asyncio.get_event_loop() + # returns a Task object, not the result objects themselves. You have to access the Task result + # to see the output + result = loop.run_until_complete(supervisor()) + except Exception as e: + pass + finally: + loop.close() diff --git a/coroutine_chaining.py b/coroutine_chaining.py new file mode 100644 index 0000000..ba5fb2b --- /dev/null +++ b/coroutine_chaining.py @@ -0,0 +1,32 @@ +""" +Here is a trivial example of us awaiting the result of another coroutine. We did this by using the await +keyword before calling it. The await keyword gives control back to the event loop and registers add_42(23) function +and arguments call to the Task Queue allowing the event loop to schedule other tasks. In this case this +single function is the only Task on the Queue so it will be picked up and executed. Once executed the result is +returned to hello_async allowing it to be resumed by the event loop scheduler. +""" + +import asyncio + + +async def add_42(number): + if not isinstance(number, int): + raise ValueError("You need to supply a number to this bitch") + print("Adding 42") + return 42 + number + + +async def hello_async(): + print("Hello async!") + co_result = await add_42(23) + return co_result + + +event_loop = asyncio.get_event_loop() + +try: + print("Entering event loop") + result = event_loop.run_until_complete(hello_async()) + print(result) +finally: + event_loop.close() diff --git a/hello_coroutine.py b/hello_coroutine.py new file mode 100644 index 0000000..48efe2c --- /dev/null +++ b/hello_coroutine.py @@ -0,0 +1,24 @@ +""" +Once asyncio has created an event loop,an application registers the functions to call back when a specific event happens: + as time passes, a file descriptor is ready to be read,or a socket is ready to be written. That type of function is + called a coroutine. It is a particular type of function that can give back control to the caller so that the event loop + can continue running. +""" +import asyncio + +# Adding the async keyword makes this a coroutine object +async def hello_world(): + print('Hello world') + return 42 + + +hello_world_coroutine = hello_world() +print(hello_world_coroutine) + +event_loop = asyncio.get_event_loop() +try: + print('Entering the event loop') + result = event_loop.run_until_complete(hello_world_coroutine) + print(result) +finally: + event_loop.close() \ No newline at end of file diff --git a/sleep_gather.py b/sleep_gather.py new file mode 100644 index 0000000..91407fc --- /dev/null +++ b/sleep_gather.py @@ -0,0 +1,21 @@ +import asyncio + + +async def hello_async(): + print('Hello Async!') + + +async def hello_python(): + print('Hello Python') + await asyncio.sleep(0.1) + +event_loop = asyncio.get_event_loop() +try: + result = event_loop.run_until_complete(asyncio.gather( + hello_async(), + hello_python(), + hello_python(), + )) + print(result) +finally: + event_loop.close() \ No newline at end of file diff --git a/sync_socket.py b/sync_socket.py new file mode 100644 index 0000000..429a17e --- /dev/null +++ b/sync_socket.py @@ -0,0 +1,20 @@ +""" +Here we have turned was was a synchronous call into an async call with the use of the select module. +select is old however and OSs have newer system calls. Asyncio abstracts the system calls out, and +gives us primitives to build better async code. + +""" + +import select +import socket + +s = socket.create_connection(("httpbin.org", 80)) +s.send(b"GET /delay/5 HTTP/1.1\r\nHost: httpbin.org\r\n\r\n") +s.setblocking(False) + +while True: + ready_to_read, ready_to_write, in_error = select.select([s], [], []) + if s in ready_to_read: + buf = s.recv(1024) + print(buf) + break \ No newline at end of file