SlideShare a Scribd company logo
1 of 71
Deep Dive into
Coroutine
김대희
Environment
- OS : macOS High Sierra (10.13.6)
- Version : CPython 3.6.5
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
$ python coroutine.py
coro1 first entry point
coro2 first entry point
coro1 second entry point
coro2 second entry point→ →
→ →
→ →
→ →
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
$ python coroutine.py
coro1 first entry point
coro2 first entry point
coro1 second entry point
coro2 second entry point
Multiple Entry Points
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
→ →
→ →
→ →
→ →
→ →
→ →
→ →
Resuming(Entry points)
- First lines of functions are
entry points.
- Lines after `await` can be
resumed(entry points) if the
`await` suspends.
→ →
Suspending
- `await` means it may suspend
but not always.
In [1]:
In [2]:
In [3]:
...:
...:
...:
...:
...:
...:
In [4]:
In [5]:
import inspect
frame = None
def func():
global frame
x = 10
y = 20
print(x + y)
frame = inspect.currentframe()
func()
30
clear
Frame object
- Contains information for
executing a function.
In [6]: f_localsframe.
frame.f_locals frame.f_lasti
frame.f_back frame.f_code
frame.f_locals
f_locals
- Local variables are stored
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]:
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: f_backframe.
f_locals
- Local variables are stored
frame.f_locals frame.f_lasti
frame.f_back frame.f_codeframe.f_back
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
ThreadState
frame
Frame
f_back
Frame
f_back
Frame
f_back
→ Reference
→ Call
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]:
frame.f_locals frame.f_lasti
frame.f_back frame.f_code
frame.f_lasti
frame.f_lasti
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]: frame.f_lasti
Out[8]: 30
In [9]:
In [1]:
In [2]:
In [1]:
In [2]:
In [3]:
...:
...:
...:
...:
...:
...:
import inspect
frame = None
def func():
global frame
x = 10
y = 20
print(x + y)
frame = inspect.currentframe()
import dis
dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 1 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
.
.
28 LOAD_CONST 0 (None)
30 RETURN_VALUE→ →
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
f_lasti
- Index of last attempted
instruction in bytecode.
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]: frame.f_lasti
Out[8]: 30
In [9]:
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]: frame.f_lasti
Out[8]: 30
In [9]:
frame.f_locals frame.f_lasti
frame.f_back frame.f_codeframe.f_code
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
f_lasti
- Index of last attempted
instruction in bytecode.frame..f_code
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]: frame.f_lasti
Out[8]: 30
In [9]: frame.f_code
code.co_consts code.co_varnames
code.co_names code.co_code
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
f_lasti
- Index of last attempted
instruction in bytecode.is func.__code__
Out[9]: True
In[10]: code = frame.f_code
In[11]: code.
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y) Code Line Number
Bytecode index
Opcode
Operand
Operand value
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
print(func.__code__.co_code)
>> b'dx01}x00dx02}x01tx00|x00|x01x17
x00x83x01x01x00dx00Sx00’
print(list(func.__code__.co_code))
>> [100, 1, 125, 0, 100, 2, 125, 1, 116, 0,
124, 0, 124, 1, 23, 0, 131, 1, 1, 0, 100, 0,
83, 0]
import opcode
print(opcode.opname[100])
>> ‘LOAD_CONST’
# test.py
def func():
x = 10
y = 20
print(x + y)
print(func.__code__.co_consts)
>> (None, 10, 20)
print(func.__code__.co_varnames)
>> ('x', 'y')
print(func.__code__.co_names)
>> ('print’,)
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
code.co_names
0 print
frame.f_local
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
10
frame.f_local
Mutable
Immutable
code.co_names
0 print
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack frame.f_local
x 10
Mutable
Immutable
code.co_names
0 print
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
20
frame.f_local
x 10
Mutable
Immutable
code.co_names
0 print
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
print
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
print
10
20
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
print
30
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
print
30
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
None
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
None
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
# test.py
def func():
x = 10
y = 20
print(x + y)
Value stack
code.co_names
0 print
frame.f_local
x 10
y 20
code.co_consts
0 None
1 10
2 20
code.co_varnames
0 x
1 y
Mutable
Immutable
In [1]: import dis
In [2]: from test import func
In [3]: dis.dis(func)
2 0 LOAD_CONST 1 (10)
2 STORE_FAST 0 (x)
3 4 LOAD_CONST 2 (20)
6 STORE_FAST 1 (y)
4 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (x)
12 LOAD_FAST 1 (y)
14 BINARY_ADD
16 CALL_FUNCION 1
18 POP_TOP
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
f_locals
- Local variables are stored
f_back
- Previous stack frame, this
frame’s caller
f_lasti
- Index of last attempted
instruction in bytecode.
f_code
- co_consts
- Constant values
- co_names
- Global variable names
- co_varnames
- Local variable names
- co_code
- Complied bytecode
In [6]: frame.f_locals
Out[6]: {‘x’: 10, ‘y’: 20}
In [7]: frame.f_back
Out[7]: <frame ...>
In [8]: frame.f_lasti
Out[8]: 30
In [9]: frame.f_code is func.__code__
Out[9]: True
In[10]: code = frame.f_code
In[11]: code.
code.co_consts code.co_varnames
code.co_names code.co_code
In [1]: import dis
In [2]: dis.dis(coroutine1)
...
3 8 LOAD_GLOBAL 1 (asyncio)
10 LOAD_ATTR 2 (sleep)
12 LOAD_CONST 2 (1)
14 CALL_FUNCTION 1
16 GET_AWAITABLE
18 LOAD_CONST 0 (None)
20 YIELD_FROM
22 POP_TOP
...
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
import asyncio
@asyncio.coroutine
def coroutine3():
print(“coro1 first entry point”)
yield from asyncio.sleep(1)
print(“coro1 second entry point”)
In [1]: import dis
In [2]: dis.dis(coroutine1)
...
3 8 LOAD_GLOBAL 1 (asyncio)
10 LOAD_ATTR 2 (sleep)
12 LOAD_CONST 2 (1)
14 CALL_FUNCTION 1
16 GET_YIELD_FROM_ITER
18 LOAD_CONST 0 (None)
20 YIELD_FROM
22 POP_TOP
...
YIELD_FROM
- Delegating to a subgenerator
- Both coroutines use ‘YIELD_FROM’.
def generator():
recv = yield 1
return recv
gen = generator()
gen.send(None)
1
gen.send(2)
2
In [1]:
In [2]:
Out[2]:
In [3]:
StopIteration:
def generator():
recv = yield 1
return recv
2 0 LOAD_CONST 1 (1)
2 YIELD_VALUE
4 STORE_FAST 0 (recv)
3 6 LOAD_FAST 0 (recv)
8 RETURN_VALUE
In [1]: gen = generator()
In [2]: gen.send(None)
Out[2]: 1
lasti = gen.gi_frame.f_lasti
lasti
2
code = gen.gi_code
code is gen.gi_frame.f_code
True
op = code[lasti]
import opcode
opcode.opname[op]
‘YIELD_VALUE’
In [3]:
In [4]:
Out[4]:
In [5]:
In [6]:
Out[6]:
In [7]:
In [8]:
In [9]:
Out[9]:
async def coroutine():
pass
In [1]: coro = coroutine()
In [2]: coro.cr_frame
Out[2]: <frame at ...>
In [3]: coro.cr_code
Out[3]: <code object coroutine at ...>
In [1]: gen = generator()
In [2]: gen.send(None)
Out[2]: 1
In [3]: gen.send(2)
StopIteration: 2
static PyObject *gen_send_ex(PyGenObject *gen,
PyObject *arg, int exc, int closing)
{
PyThreadState *tstate =
PyThreadState_GET();
PyFrameObject *f = gen->gi_frame;
PyObject *result;
result = arg ? arg : Py_None;
Py_INCREF(result);
*(f->f_stacktop++) = result;
f->f_back = tstate->frame;
result = PyEval_EvalFrameEx(f, exc);
Py_CLEAR(f->f_back);
...
PyEval_EvalFrameEx
- The code object associated
with the execution frame is
executed, interpreting
bytecode and executing calls
as needed.
PyObject *PyEval_EvalFrameEx(PyFrameObject *f,
int throwflag){
PyThreadState *tstate =
PyThreadState_GET();
tstate->frame = f;
main_loop:
for (;;) {
f->f_lasti = INSTR_OFFSET();
switch (opcode) {
case: LOAD_FAST {
...
}
case: LOAD_CONST {
...
}
}
tstate->frame = f->f_back;
...
Frame object
- Used on executing a function
- Contains information for executing a function
- Call stack
- Value stack
- Local variables
- Last attempted bytecode instruction
Coroutine
- Based on generator
- Contains a frame object like thread state
- The frame memorizes which index of bytecode is executed.
- The frame stores local variables.
Frame f_back
f_locals
f_lasti
f_code co_consts
co_varnames
co_names
co_code
value stack
Frame f_back
f_locals
f_lasti
f_code co_consts
co_varnames
co_names
co_code
value stack
Frame f_back
f_locals
f_lasti
f_code co_consts
co_varnames
co_names
co_code
value stack
Frame f_bac
f_loc
f_las
f_cod
value
Frame f_back
f_locals
f_lasti
ThreadState
frame
Coroutine
gi_frame(cr_frame)
Event Loop for non-preemptive multitasking
Get an event loop from this
thread.
Schedule ‘coroutine1’ to the
event loop as a task.
Schedule ‘coroutine2’ to the
event loop as a task.
Run the event loop executing
scheduled tasks.
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
# coroutine.py
import asyncio
async def coroutine1():
print(“coro1 first entry point”)
await asyncio.sleep(1)
print(“coro1 second entry point”)
async def coroutine2():
print(“coro2 first entry point”)
await asyncio.sleep(2)
print(“coro2 second entry point”)
loop = asyncio.get_event_loop()
loop.create_task(coroutine1())
loop.create_task(coroutine2())
loop.run_forever()
await asyncio.sleep(1)
await asyncio.sleep(2)
Get an event loop from this
thread.
Schedule ‘coroutine1’ to the
event loop as a task.
Schedule ‘coroutine2’ to the
event loop as a task.
Run the event loop executing
scheduled tasks.
async def sleep(delay, result=None, *, loop=None):
if delay <= 0:
await __sleep0()
return result
if loop is None:
loop = events.get_event_loop()
future = loop.create_future()
h = loop.call_later(delay,
future.set_result,
future, result)
return await future
@types.coroutine
def __sleep0():
yield
# the code has been modified for your better understanding
class Future:
def __await__(self):
if not self.done():
yield self # This tells Task to wait for completion.
if not self.done():
raise RuntimeError("await wasn't used with future")
return self.result()
__iter__ = __await__ # make compatible with 'yield from’.
# the code has been modified for your better understanding
class Task(Future):
def _step(self):
try:
result = self.coro.send(None)
except StopIteration as exc:
self.set_result(exc.value)
except Exception as exc:
self.set_exception(exc)
else:
if result is None:
self._loop.call_soon(self._step)
elif isinstance(result, Future):
result.add_done_callback(self._step)
# the code has been modified for your better understanding
class Task(Future):
def __init__(self, coro, *, loop=None):
super().__init__(loop=loop)
self._coro = coro
self._loop.call_soon(self._step)
...
# the code has been modified for your better understanding
class Future:
def add_done_callback(self, fn):
self._callbacks.append(fn)
def set_result(self, result):
self._result = result
self._state = _FINISHED
self._schedule_callbacks()
def _schedule_callbacks(self):
callbacks = self._callbacks[:]
if not callbacks:
return
self._callbacks[:] = []
for callback in callbacks:
self._loop.call_soon(callback, self)
# the code has been modified for your better understanding
Event Loop
Task._step
if result is None
Scheduled by call_soon
Task
result = coroutine.send(None)
Event Loop
Task._step
if result is None
Scheduled by call_soon
Task
result = coroutine.send(None)
Scheduled by call_soon
Event Loop
Task._step
if result is None
Scheduled by call_soon
Task
result = coroutine.send(None)
if result is Future
Future
Future.callbacksAdded by add_done_callback
Future.set_result
Scheduled by call_soon
Scheduled by call_soon
class Handle:
def __init__(self, callback, args, loop):
self._callback = callback
self._args = args
self._loop = loop
def _run(self):
self._callback(*self._args)
class TimerHandle(Handle):
def __init__(self, when, callback, args, loop):
super().__init__(callback, args, loop)
self._when = when
def __gt__(self, other):
return self._when > other._when
...
# the code has been modified for your better understanding
class CustomEventLoop(AbstractEventLoop):
def create_future(self):
return Future(loop=self)
def create_task(self, coro):
return Task(coro, loop=self)
def time(self):
return time.monotonic()
def get_debug(self):
pass
def _timer_handle_cancelled(self, handle):
pass
# the code has been modified for your better understanding
class CustomEventLoop(AbstractEventLoop):
def __init__(self):
self._scheduled = []
self._ready = deque()
def call_soon(self, callback, *args):
handle = Handle(callback, args, self)
self._ready.append(handle)
return handle
def call_later(self, delay, callback, *args):
timer = self.call_at(self.time() + delay, callback, *args)
return timer
def call_at(self, when, callback, *args):
timer = TimerHandle(when, callback, args, self)
heappush(self._scheduled, timer)
return timer
# the code has been modified for your better understanding
class CustomEventLoop(AbstractEventLoop):
def run_forever(self):
while True:
self._run_once()
# the code has been modified for your better understanding
class CustomEventLoop(AbstractEventLoop):
def _run_once(self):
while self._scheduled and self._scheduled[0]._when <= self.time():
timer = heappop(self._scheduled)
self._ready.append(timer)
len_ready = len(self._ready)
for _ in range(len_ready):
handle = self._ready.popleft()
handle._run()
timeout = 0
if self._scheduled and not self._ready:
timeout = max(0, self._scheduled[0]._when - self.time())
time.sleep(timeout)
# the code has been modified for your better understanding
timeout = 0
if self._scheduled and not self._ready:
timeout = max(0, self._scheduled[0]._when - self.time())
time.sleep(timeout)
Spinning if ‘timeout’ is zero
Freezing if ‘timeout’ is like infinity
Selector
 SelectSelector
 PollSelector
 EpollSelector
 KqueueSelector
 DevpollSelector
DefaultSelector
– An alias to the most efficient implementation available on the current platform
# main thread
import selectors
import socket
ssocket, csocket = socket.socketpair()
ssocket.setblocking(False)
csocket.setblocking(False)
selector = selectors.DefaultSelector()
selector.register(ssocket.fileno(), selectors.EVENT_READ)
selector.select(timeout=None) # waiting
ssocket.recv(1) # b’0’
# other threads
csocket.send(b’0’)
class CustomEventLoop(AbstractEventLoop):
def __init__(self):
self._scheduled = []
self._ready = deque()
self._selector = selectors.DefaultSelector()
self._ssocket, self._csocket = socket.socketpair()
self._ssocket.setblocking(False)
self._csocket.setblocking(False)
self._selector.register(self._ssocket.fileno(), selectors.EVENT_READ)
def call_soon_threadsafe(self, callback, *args):
handle = self.call_soon(callback, *args)
self._csocket.send(b'0')
return handle
# the code has been modified for your better understanding
timeout = None
if self._ready:
timeout = 0
elif self._scheduled:
timeout = max(0, self._scheduled[0]._when - self.time())
events = self._selector.select(timeout)
if events:
self._ssocket.recv(1)
timeout = 0
if self._scheduled and not self._ready:
timeout = max(0, self.time() - self._scheduled[0]._when)
time.sleep(timeout)
# the code has been modified for your better understanding
Demo
Thank you

More Related Content

What's hot

いつやるの?Git入門 v1.1.0
いつやるの?Git入門 v1.1.0いつやるの?Git入門 v1.1.0
いつやるの?Git入門 v1.1.0Masakazu Matsushita
 
네이버 오픈세미나 백엔드_아키텍쳐
네이버 오픈세미나 백엔드_아키텍쳐네이버 오픈세미나 백엔드_아키텍쳐
네이버 오픈세미나 백엔드_아키텍쳐NAVER D2
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례Hyung Lee
 
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )博宣 今村
 
엘라스틱서치 이해하기 20160613
엘라스틱서치 이해하기 20160613엘라스틱서치 이해하기 20160613
엘라스틱서치 이해하기 20160613Yong Joon Moon
 
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용Terry Cho
 
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판BJ Jang
 
Web assembly 맛보기
Web assembly 맛보기Web assembly 맛보기
Web assembly 맛보기GyeongSeok Seo
 
PHPUnit - jak zacząć pisać testy automatyczne [PL]
PHPUnit - jak zacząć pisać testy automatyczne [PL]PHPUnit - jak zacząć pisać testy automatyczne [PL]
PHPUnit - jak zacząć pisać testy automatyczne [PL]Droptica
 
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진PgDay.Seoul
 
How To Become Better Engineer
How To Become Better EngineerHow To Become Better Engineer
How To Become Better EngineerDaeMyung Kang
 
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptx
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptxAws Batchを用いたサーバレスな競馬スクレイピング環境.pptx
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptxShichijoYuhi
 
A python web service
A python web serviceA python web service
A python web serviceTemian Vlad
 
Using Git/Gerrit and Jenkins to Manage the Code Review Processord
Using Git/Gerrit and Jenkins to Manage the Code Review ProcessordUsing Git/Gerrit and Jenkins to Manage the Code Review Processord
Using Git/Gerrit and Jenkins to Manage the Code Review ProcessordMarc Karasek
 
혼자서 만드는 MMO게임 서버
혼자서 만드는 MMO게임 서버혼자서 만드는 MMO게임 서버
혼자서 만드는 MMO게임 서버iFunFactory Inc.
 
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기Chanwoong Kim
 

What's hot (16)

いつやるの?Git入門 v1.1.0
いつやるの?Git入門 v1.1.0いつやるの?Git入門 v1.1.0
いつやるの?Git入門 v1.1.0
 
네이버 오픈세미나 백엔드_아키텍쳐
네이버 오픈세미나 백엔드_아키텍쳐네이버 오픈세미나 백엔드_아키텍쳐
네이버 오픈세미나 백엔드_아키텍쳐
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례
 
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )
Linuxベースのオープンソース フライトコントローラーの概要( #ABC2015S )
 
엘라스틱서치 이해하기 20160613
엘라스틱서치 이해하기 20160613엘라스틱서치 이해하기 20160613
엘라스틱서치 이해하기 20160613
 
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용
14회 jco 컨퍼런스 조대협의 소프트웨어 개발 배포용
 
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판
Open Source GIS 기초교육 4일차 - GeoServer 기초 2014년 7월판
 
Web assembly 맛보기
Web assembly 맛보기Web assembly 맛보기
Web assembly 맛보기
 
PHPUnit - jak zacząć pisać testy automatyczne [PL]
PHPUnit - jak zacząć pisać testy automatyczne [PL]PHPUnit - jak zacząć pisać testy automatyczne [PL]
PHPUnit - jak zacząć pisać testy automatyczne [PL]
 
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진
[Pgday.Seoul 2017] 1. PostGIS의 사례로 본 PostgreSQL 확장 - 장병진
 
How To Become Better Engineer
How To Become Better EngineerHow To Become Better Engineer
How To Become Better Engineer
 
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptx
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptxAws Batchを用いたサーバレスな競馬スクレイピング環境.pptx
Aws Batchを用いたサーバレスな競馬スクレイピング環境.pptx
 
A python web service
A python web serviceA python web service
A python web service
 
Using Git/Gerrit and Jenkins to Manage the Code Review Processord
Using Git/Gerrit and Jenkins to Manage the Code Review ProcessordUsing Git/Gerrit and Jenkins to Manage the Code Review Processord
Using Git/Gerrit and Jenkins to Manage the Code Review Processord
 
혼자서 만드는 MMO게임 서버
혼자서 만드는 MMO게임 서버혼자서 만드는 MMO게임 서버
혼자서 만드는 MMO게임 서버
 
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
 

Similar to PyconKR 2018 Deep dive into Coroutine

The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184Mahmoud Samir Fayed
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015Michiel Borkent
 
The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181Mahmoud Samir Fayed
 
Go Programming Language (Golang)
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)Ishin Vin
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
Python Yield
Python YieldPython Yield
Python Yieldyangjuven
 
The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31Mahmoud Samir Fayed
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptxGuy Komari
 
2.1 ### uVision Project, (C) Keil Software .docx
2.1   ### uVision Project, (C) Keil Software    .docx2.1   ### uVision Project, (C) Keil Software    .docx
2.1 ### uVision Project, (C) Keil Software .docxtarifarmarie
 
The Ring programming language version 1.7 book - Part 30 of 196
The Ring programming language version 1.7 book - Part 30 of 196The Ring programming language version 1.7 book - Part 30 of 196
The Ring programming language version 1.7 book - Part 30 of 196Mahmoud Samir Fayed
 
Pydiomatic
PydiomaticPydiomatic
Pydiomaticrik0
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance PuzzlersDoug Hawkins
 
The Ring programming language version 1.9 book - Part 40 of 210
The Ring programming language version 1.9 book - Part 40 of 210The Ring programming language version 1.9 book - Part 40 of 210
The Ring programming language version 1.9 book - Part 40 of 210Mahmoud Samir Fayed
 
The Ring programming language version 1.10 book - Part 35 of 212
The Ring programming language version 1.10 book - Part 35 of 212The Ring programming language version 1.10 book - Part 35 of 212
The Ring programming language version 1.10 book - Part 35 of 212Mahmoud Samir Fayed
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android UpdateGarth Gilmour
 

Similar to PyconKR 2018 Deep dive into Coroutine (20)

The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
PythonOOP
PythonOOPPythonOOP
PythonOOP
 
Mcq cpup
Mcq cpupMcq cpup
Mcq cpup
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181The Ring programming language version 1.5.2 book - Part 26 of 181
The Ring programming language version 1.5.2 book - Part 26 of 181
 
Go Programming Language (Golang)
Go Programming Language (Golang)Go Programming Language (Golang)
Go Programming Language (Golang)
 
Android and cpp
Android and cppAndroid and cpp
Android and cpp
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
Python Yield
Python YieldPython Yield
Python Yield
 
The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31The Ring programming language version 1.5 book - Part 5 of 31
The Ring programming language version 1.5 book - Part 5 of 31
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
 
2.1 ### uVision Project, (C) Keil Software .docx
2.1   ### uVision Project, (C) Keil Software    .docx2.1   ### uVision Project, (C) Keil Software    .docx
2.1 ### uVision Project, (C) Keil Software .docx
 
The Ring programming language version 1.7 book - Part 30 of 196
The Ring programming language version 1.7 book - Part 30 of 196The Ring programming language version 1.7 book - Part 30 of 196
The Ring programming language version 1.7 book - Part 30 of 196
 
Pydiomatic
PydiomaticPydiomatic
Pydiomatic
 
Python idiomatico
Python idiomaticoPython idiomatico
Python idiomatico
 
Java Performance Puzzlers
Java Performance PuzzlersJava Performance Puzzlers
Java Performance Puzzlers
 
The Ring programming language version 1.9 book - Part 40 of 210
The Ring programming language version 1.9 book - Part 40 of 210The Ring programming language version 1.9 book - Part 40 of 210
The Ring programming language version 1.9 book - Part 40 of 210
 
The Ring programming language version 1.10 book - Part 35 of 212
The Ring programming language version 1.10 book - Part 35 of 212The Ring programming language version 1.10 book - Part 35 of 212
The Ring programming language version 1.10 book - Part 35 of 212
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 

Recently uploaded

Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Developmentvyaparkranti
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 

Recently uploaded (20)

Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Development
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 

PyconKR 2018 Deep dive into Coroutine

  • 2. Environment - OS : macOS High Sierra (10.13.6) - Version : CPython 3.6.5
  • 3. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever()
  • 4. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever() $ python coroutine.py coro1 first entry point coro2 first entry point coro1 second entry point coro2 second entry point→ → → → → → → →
  • 5. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever() $ python coroutine.py coro1 first entry point coro2 first entry point coro1 second entry point coro2 second entry point
  • 7. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever() → → → → → → → → → → → → → → Resuming(Entry points) - First lines of functions are entry points. - Lines after `await` can be resumed(entry points) if the `await` suspends. → → Suspending - `await` means it may suspend but not always.
  • 8. In [1]: In [2]: In [3]: ...: ...: ...: ...: ...: ...: In [4]: In [5]: import inspect frame = None def func(): global frame x = 10 y = 20 print(x + y) frame = inspect.currentframe() func() 30 clear Frame object - Contains information for executing a function.
  • 9. In [6]: f_localsframe. frame.f_locals frame.f_lasti frame.f_back frame.f_code frame.f_locals
  • 10. f_locals - Local variables are stored In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]:
  • 11. In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: f_backframe. f_locals - Local variables are stored frame.f_locals frame.f_lasti frame.f_back frame.f_codeframe.f_back
  • 12. f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> ThreadState frame Frame f_back Frame f_back Frame f_back → Reference → Call
  • 13. f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_locals frame.f_lasti frame.f_back frame.f_code frame.f_lasti frame.f_lasti
  • 14. f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_lasti Out[8]: 30 In [9]:
  • 15. In [1]: In [2]: In [1]: In [2]: In [3]: ...: ...: ...: ...: ...: ...: import inspect frame = None def func(): global frame x = 10 y = 20 print(x + y) frame = inspect.currentframe() import dis dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 1 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) . . 28 LOAD_CONST 0 (None) 30 RETURN_VALUE→ →
  • 16. f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller f_lasti - Index of last attempted instruction in bytecode. In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_lasti Out[8]: 30 In [9]:
  • 17. In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_lasti Out[8]: 30 In [9]: frame.f_locals frame.f_lasti frame.f_back frame.f_codeframe.f_code f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller f_lasti - Index of last attempted instruction in bytecode.frame..f_code
  • 18. In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_lasti Out[8]: 30 In [9]: frame.f_code code.co_consts code.co_varnames code.co_names code.co_code f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller f_lasti - Index of last attempted instruction in bytecode.is func.__code__ Out[9]: True In[10]: code = frame.f_code In[11]: code.
  • 19. In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE # test.py def func(): x = 10 y = 20 print(x + y) Code Line Number Bytecode index Opcode Operand Operand value
  • 20. In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE # test.py def func(): x = 10 y = 20 print(x + y) print(func.__code__.co_code) >> b'dx01}x00dx02}x01tx00|x00|x01x17 x00x83x01x01x00dx00Sx00’ print(list(func.__code__.co_code)) >> [100, 1, 125, 0, 100, 2, 125, 1, 116, 0, 124, 0, 124, 1, 23, 0, 131, 1, 1, 0, 100, 0, 83, 0] import opcode print(opcode.opname[100]) >> ‘LOAD_CONST’
  • 21. # test.py def func(): x = 10 y = 20 print(x + y) print(func.__code__.co_consts) >> (None, 10, 20) print(func.__code__.co_varnames) >> ('x', 'y') print(func.__code__.co_names) >> ('print’,) In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 22. # test.py def func(): x = 10 y = 20 print(x + y) Value stack code.co_names 0 print frame.f_local code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 23. # test.py def func(): x = 10 y = 20 print(x + y) Value stack 10 frame.f_local Mutable Immutable code.co_names 0 print code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 24. # test.py def func(): x = 10 y = 20 print(x + y) Value stack frame.f_local x 10 Mutable Immutable code.co_names 0 print code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 25. # test.py def func(): x = 10 y = 20 print(x + y) Value stack 20 frame.f_local x 10 Mutable Immutable code.co_names 0 print code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 26. # test.py def func(): x = 10 y = 20 print(x + y) Value stack code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 27. # test.py def func(): x = 10 y = 20 print(x + y) Value stack print code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 28. # test.py def func(): x = 10 y = 20 print(x + y) Value stack print 10 20 code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 29. # test.py def func(): x = 10 y = 20 print(x + y) Value stack print 30 code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 30. # test.py def func(): x = 10 y = 20 print(x + y) Value stack print 30 code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 31. # test.py def func(): x = 10 y = 20 print(x + y) Value stack None code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 32. # test.py def func(): x = 10 y = 20 print(x + y) Value stack code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 33. # test.py def func(): x = 10 y = 20 print(x + y) Value stack None code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 34. # test.py def func(): x = 10 y = 20 print(x + y) Value stack code.co_names 0 print frame.f_local x 10 y 20 code.co_consts 0 None 1 10 2 20 code.co_varnames 0 x 1 y Mutable Immutable In [1]: import dis In [2]: from test import func In [3]: dis.dis(func) 2 0 LOAD_CONST 1 (10) 2 STORE_FAST 0 (x) 3 4 LOAD_CONST 2 (20) 6 STORE_FAST 1 (y) 4 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (x) 12 LOAD_FAST 1 (y) 14 BINARY_ADD 16 CALL_FUNCION 1 18 POP_TOP 20 LOAD_CONST 0 (None) 22 RETURN_VALUE
  • 35. f_locals - Local variables are stored f_back - Previous stack frame, this frame’s caller f_lasti - Index of last attempted instruction in bytecode. f_code - co_consts - Constant values - co_names - Global variable names - co_varnames - Local variable names - co_code - Complied bytecode In [6]: frame.f_locals Out[6]: {‘x’: 10, ‘y’: 20} In [7]: frame.f_back Out[7]: <frame ...> In [8]: frame.f_lasti Out[8]: 30 In [9]: frame.f_code is func.__code__ Out[9]: True In[10]: code = frame.f_code In[11]: code. code.co_consts code.co_varnames code.co_names code.co_code
  • 36. In [1]: import dis In [2]: dis.dis(coroutine1) ... 3 8 LOAD_GLOBAL 1 (asyncio) 10 LOAD_ATTR 2 (sleep) 12 LOAD_CONST 2 (1) 14 CALL_FUNCTION 1 16 GET_AWAITABLE 18 LOAD_CONST 0 (None) 20 YIELD_FROM 22 POP_TOP ... import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”)
  • 37. import asyncio @asyncio.coroutine def coroutine3(): print(“coro1 first entry point”) yield from asyncio.sleep(1) print(“coro1 second entry point”) In [1]: import dis In [2]: dis.dis(coroutine1) ... 3 8 LOAD_GLOBAL 1 (asyncio) 10 LOAD_ATTR 2 (sleep) 12 LOAD_CONST 2 (1) 14 CALL_FUNCTION 1 16 GET_YIELD_FROM_ITER 18 LOAD_CONST 0 (None) 20 YIELD_FROM 22 POP_TOP ...
  • 38. YIELD_FROM - Delegating to a subgenerator - Both coroutines use ‘YIELD_FROM’.
  • 39. def generator(): recv = yield 1 return recv gen = generator() gen.send(None) 1 gen.send(2) 2 In [1]: In [2]: Out[2]: In [3]: StopIteration:
  • 40. def generator(): recv = yield 1 return recv 2 0 LOAD_CONST 1 (1) 2 YIELD_VALUE 4 STORE_FAST 0 (recv) 3 6 LOAD_FAST 0 (recv) 8 RETURN_VALUE In [1]: gen = generator() In [2]: gen.send(None) Out[2]: 1 lasti = gen.gi_frame.f_lasti lasti 2 code = gen.gi_code code is gen.gi_frame.f_code True op = code[lasti] import opcode opcode.opname[op] ‘YIELD_VALUE’ In [3]: In [4]: Out[4]: In [5]: In [6]: Out[6]: In [7]: In [8]: In [9]: Out[9]:
  • 41. async def coroutine(): pass In [1]: coro = coroutine() In [2]: coro.cr_frame Out[2]: <frame at ...> In [3]: coro.cr_code Out[3]: <code object coroutine at ...>
  • 42. In [1]: gen = generator() In [2]: gen.send(None) Out[2]: 1 In [3]: gen.send(2) StopIteration: 2 static PyObject *gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) { PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; PyObject *result; result = arg ? arg : Py_None; Py_INCREF(result); *(f->f_stacktop++) = result; f->f_back = tstate->frame; result = PyEval_EvalFrameEx(f, exc); Py_CLEAR(f->f_back); ...
  • 43. PyEval_EvalFrameEx - The code object associated with the execution frame is executed, interpreting bytecode and executing calls as needed. PyObject *PyEval_EvalFrameEx(PyFrameObject *f, int throwflag){ PyThreadState *tstate = PyThreadState_GET(); tstate->frame = f; main_loop: for (;;) { f->f_lasti = INSTR_OFFSET(); switch (opcode) { case: LOAD_FAST { ... } case: LOAD_CONST { ... } } tstate->frame = f->f_back; ...
  • 44. Frame object - Used on executing a function - Contains information for executing a function - Call stack - Value stack - Local variables - Last attempted bytecode instruction Coroutine - Based on generator - Contains a frame object like thread state - The frame memorizes which index of bytecode is executed. - The frame stores local variables.
  • 49. Event Loop for non-preemptive multitasking
  • 50. Get an event loop from this thread. Schedule ‘coroutine1’ to the event loop as a task. Schedule ‘coroutine2’ to the event loop as a task. Run the event loop executing scheduled tasks. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever() loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever()
  • 51. # coroutine.py import asyncio async def coroutine1(): print(“coro1 first entry point”) await asyncio.sleep(1) print(“coro1 second entry point”) async def coroutine2(): print(“coro2 first entry point”) await asyncio.sleep(2) print(“coro2 second entry point”) loop = asyncio.get_event_loop() loop.create_task(coroutine1()) loop.create_task(coroutine2()) loop.run_forever() await asyncio.sleep(1) await asyncio.sleep(2) Get an event loop from this thread. Schedule ‘coroutine1’ to the event loop as a task. Schedule ‘coroutine2’ to the event loop as a task. Run the event loop executing scheduled tasks.
  • 52. async def sleep(delay, result=None, *, loop=None): if delay <= 0: await __sleep0() return result if loop is None: loop = events.get_event_loop() future = loop.create_future() h = loop.call_later(delay, future.set_result, future, result) return await future @types.coroutine def __sleep0(): yield # the code has been modified for your better understanding
  • 53. class Future: def __await__(self): if not self.done(): yield self # This tells Task to wait for completion. if not self.done(): raise RuntimeError("await wasn't used with future") return self.result() __iter__ = __await__ # make compatible with 'yield from’. # the code has been modified for your better understanding
  • 54. class Task(Future): def _step(self): try: result = self.coro.send(None) except StopIteration as exc: self.set_result(exc.value) except Exception as exc: self.set_exception(exc) else: if result is None: self._loop.call_soon(self._step) elif isinstance(result, Future): result.add_done_callback(self._step) # the code has been modified for your better understanding
  • 55. class Task(Future): def __init__(self, coro, *, loop=None): super().__init__(loop=loop) self._coro = coro self._loop.call_soon(self._step) ... # the code has been modified for your better understanding
  • 56. class Future: def add_done_callback(self, fn): self._callbacks.append(fn) def set_result(self, result): self._result = result self._state = _FINISHED self._schedule_callbacks() def _schedule_callbacks(self): callbacks = self._callbacks[:] if not callbacks: return self._callbacks[:] = [] for callback in callbacks: self._loop.call_soon(callback, self) # the code has been modified for your better understanding
  • 57. Event Loop Task._step if result is None Scheduled by call_soon Task result = coroutine.send(None)
  • 58. Event Loop Task._step if result is None Scheduled by call_soon Task result = coroutine.send(None) Scheduled by call_soon
  • 59. Event Loop Task._step if result is None Scheduled by call_soon Task result = coroutine.send(None) if result is Future Future Future.callbacksAdded by add_done_callback Future.set_result Scheduled by call_soon Scheduled by call_soon
  • 60. class Handle: def __init__(self, callback, args, loop): self._callback = callback self._args = args self._loop = loop def _run(self): self._callback(*self._args) class TimerHandle(Handle): def __init__(self, when, callback, args, loop): super().__init__(callback, args, loop) self._when = when def __gt__(self, other): return self._when > other._when ... # the code has been modified for your better understanding
  • 61. class CustomEventLoop(AbstractEventLoop): def create_future(self): return Future(loop=self) def create_task(self, coro): return Task(coro, loop=self) def time(self): return time.monotonic() def get_debug(self): pass def _timer_handle_cancelled(self, handle): pass # the code has been modified for your better understanding
  • 62. class CustomEventLoop(AbstractEventLoop): def __init__(self): self._scheduled = [] self._ready = deque() def call_soon(self, callback, *args): handle = Handle(callback, args, self) self._ready.append(handle) return handle def call_later(self, delay, callback, *args): timer = self.call_at(self.time() + delay, callback, *args) return timer def call_at(self, when, callback, *args): timer = TimerHandle(when, callback, args, self) heappush(self._scheduled, timer) return timer # the code has been modified for your better understanding
  • 63. class CustomEventLoop(AbstractEventLoop): def run_forever(self): while True: self._run_once() # the code has been modified for your better understanding
  • 64. class CustomEventLoop(AbstractEventLoop): def _run_once(self): while self._scheduled and self._scheduled[0]._when <= self.time(): timer = heappop(self._scheduled) self._ready.append(timer) len_ready = len(self._ready) for _ in range(len_ready): handle = self._ready.popleft() handle._run() timeout = 0 if self._scheduled and not self._ready: timeout = max(0, self._scheduled[0]._when - self.time()) time.sleep(timeout) # the code has been modified for your better understanding
  • 65. timeout = 0 if self._scheduled and not self._ready: timeout = max(0, self._scheduled[0]._when - self.time()) time.sleep(timeout) Spinning if ‘timeout’ is zero Freezing if ‘timeout’ is like infinity
  • 66. Selector  SelectSelector  PollSelector  EpollSelector  KqueueSelector  DevpollSelector DefaultSelector – An alias to the most efficient implementation available on the current platform
  • 67. # main thread import selectors import socket ssocket, csocket = socket.socketpair() ssocket.setblocking(False) csocket.setblocking(False) selector = selectors.DefaultSelector() selector.register(ssocket.fileno(), selectors.EVENT_READ) selector.select(timeout=None) # waiting ssocket.recv(1) # b’0’ # other threads csocket.send(b’0’)
  • 68. class CustomEventLoop(AbstractEventLoop): def __init__(self): self._scheduled = [] self._ready = deque() self._selector = selectors.DefaultSelector() self._ssocket, self._csocket = socket.socketpair() self._ssocket.setblocking(False) self._csocket.setblocking(False) self._selector.register(self._ssocket.fileno(), selectors.EVENT_READ) def call_soon_threadsafe(self, callback, *args): handle = self.call_soon(callback, *args) self._csocket.send(b'0') return handle # the code has been modified for your better understanding
  • 69. timeout = None if self._ready: timeout = 0 elif self._scheduled: timeout = max(0, self._scheduled[0]._when - self.time()) events = self._selector.select(timeout) if events: self._ssocket.recv(1) timeout = 0 if self._scheduled and not self._ready: timeout = max(0, self.time() - self._scheduled[0]._when) time.sleep(timeout) # the code has been modified for your better understanding
  • 70. Demo