time
commandtime sleep 2
real 0m2.002s user 0m0.000s sys 0m0.001s
We will only be using the real time
def identity(x):
return x
print(sorted([2, 1, 3], key=identity))
[1, 2, 3]
from threading import Thread
def add(a, b):
print(a + b)
t = Thread(target=add, args=(1, 2))
t.start()
ThreadPoolExecutor
small tasksfrom concurrent.futures import ThreadPoolExecutor
from utils import is_prime
with ThreadPoolExecutor() as exe:
exe.map(is_prime, range(100000))
ThreadPoolExecutor
large tasksfrom concurrent.futures import ThreadPoolExecutor
from utils import cpu_task
with ThreadPoolExecutor() as exe:
exe.map(cpu_task, [7, 7, 7])
from multiprocessing import Process
def add(a, b):
print(a + b)
t = Process(target=add, args=(1, 2))
t.start()
ProcessPoolExecutor
small tasksfrom concurrent.futures import ProcessPoolExecutor
from utils import is_prime
with ProcessPoolExecutor() as exe:
exe.map(is_prime, range(100000))
ProcessPoolExecutor
large tasksfrom concurrent.futures import ProcessPoolExecutor
from utils import cpu_task
with ProcessPoolExecutor() as exe:
exe.map(cpu_task, [7, 7, 7])
async
functions are considered coroutines.async await
syntax enables definitionimport asyncio
async def add(a, b):
print(a + b)
asyncio.run(add(1, 2))
asyncio.run(func(arg1, arg2))
await func(arg1, arg2)
asyncio.create_task(func(arg1, arg2))
While waiting for external events like keyboard events or network calls to succeed, you can make use of the CPU time to run other tasks.
Fundamentally they are internally implemented using OS and hardware level interrupts
Most programs are sequential by default and run on a single CPU unless threads, process or coroutines are used
async def aenumerate(it):
for i, x in enumerate(it):
yield i, x
async for i, x in aenumerate(it):
print(i, x)
asyncio.run
await func(arg1, arg2) # incorrect
asyncio.run(func(arg1, arg2)) # correct
Always run entrypoint function using asyncio.run
await
outside a functionawait func(arg1, arg2)
Use await
inside an async function.
async def f1(arg1, arg2):
await func(arg1, arg2)
# incorrect
user = User.objects.aget(pk=1)
User.objects.aget
returns a coroutine which needs to be awaited
# correct
user = await User.objects.aget(pk=1)
User.objects.aget(pk=1).name
User.objects.aget
returns a coroutine which needs to be awaited first
(await User.objects.aget(pk=1)).name
async def view1(request):
# incorrect
User.objects.get(pk=1)
async def view1(request):
# correct
await User.objects.aget(pk=1)
def view2(request):
# incorrect
await User.objects.aget(pk=1)
def view2(request):
# correct
User.objects.get(pk=1)
async def view3(request):
users = User.objects.filter(is_superuser=False)
# incorrect
for user in users:
print(user)
async def view3(request):
users = User.objects.filter(is_superuser=False)
# correct
async for user in users:
print(user)
async def view4(request):
# incorrect
await sync_orm_func(arg1, arg2)
from asgiref import sync_to_async
async def view4(request):
# correct
func = sync_to_async(sync_orm_func)
await func(arg1, arg2)
def view5(request):
# incorrect
async_orm_func(arg1, arg2)
from asgiref import async_to_sync
def view5(request):
# correct
func = async_to_sync(async_orm_func)
func(arg1, arg2)