SlideShare ist ein Scribd-Unternehmen logo
1 von 33
Introducing to asynchronous
programming
Oleksandr Fedorov
• Software Engineer.
• More than 5 years in Python.
• 1.5 years of QA Automation.
E-mail: a.g.fedorof@gmail.com
Skype ID: a.g.fedorof
Agenda
1. The evolution of a loop.
2. We will call you back.
3. The Future is here.
4. Await asynchronously.
BDD with Python
Part 1 - The evolution of a loop
The evolution of a loop
from anykey import get_key
def loop():
while True:
key = get_key()
if key is not None:
break
if __name__ == '__main__':
loop()
The evolution of a loop
Tasks: 183 total, 2 running, 181 sleeping, 0 stopped, 0 zombie
PID USER PR NI SHR S %CPU %MEM TIME+ COMMAND
1949 alex 20 0 4408 R 99,7 0,1 0:29.94 python
1602 alex 20 0 28484 S 3,7 1,2 6:20.05 Viber
29713 alex 20 0 79952 S 2,0 1,9 1:41.21 skype
640 root 20 0 23980 S 1,3 0,4 2:29.21 Xorg
The evolution of a loop
import time
from anykey import get_key
def loop():
while True:
key = get_key()
if key is not None:
break
time.sleep(0.5)
if __name__ == '__main__':
loop()
The evolution of a loop – `select` example.
# twisted/internet/selectreactor.py
# class SelectReactor... Kinda of.
def doSelect(self, timeout):
r, w, ignored = _select(self._reads,
self._writes,
[], timeout)
for selectables, method in ((r, "doRead"), (w, "doWrite")):
for selectable in selectables:
self._doReadOrWrite(selectable, method)
The evolution of a loop. I/O loops.
# Our example
loop() # Twisted
from twisted.internet import reactor
reactor.run()
# Tornado
import tornado.ioloop
tornado.ioloop.IOLoop.current().start()
# pygame
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.display.flip()
# Tkinter
App().mainloop()
# Asyncio
import asyncio
asyncio.get_event_loop().run_forever()
# JavaScript
/* Nothing to do, it already runs */
Part 2 – We will call you back
We will call you back
def loop():
while True:
key = get_key()
if key == 'q':
break
if __name__ == '__main__':
loop()
We will call you back
def loop():
while True:
key = get_key()
if key == 'a':
go_left()
elif key == 'b':
...
elif key == 'c':
...
elif key == 'q':
break
if __name__ == '__main__':
loop()
def loop(callbacks):
while True:
key = get_key()
if key in callbacks:
callbacks[key]()
elif key == 'q':
break
if __name__ == '__main__':
loop({
'a': go_left,
'b': ...,
'c': ...,
})
We will call you back - jQuery
$.ajax({
url: "page.html",
success: function(){
alert("done");
}
});
$.ajax({
statusCode: {
404: function() {
alert( "page not found" );
}
}
});
We will call you back - Tkinter
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
...
self.createWidgets()
def createWidgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "click me"
self.hi_there["command"] = self.say_hi
self.QUIT = tk.Button(self, text="QUIT", fg="red",
command=root.destroy)
def say_hi(self):
print("hi there, everyone!")
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Part 3 – The Future is here
The Future is here
Future (aka Deferred, aka Promise)
• Composite of callbacks.
• Callbacks can be added in both "pending" and "done" states.
• The result passed to a future is propagated to its callbacks.
• It's possible to propagate errors (exceptions).
The Future is here – Simple example
class Future:
_nope = object()
def __init__(self):
self._callbacks = []
self._result = self._nope
def add_callback(self, function,
*args, **kwargs):
future = Future()
self._callbacks.append(
(function, args, kwargs, future))
if self._result != self._nope:
self.done(self._result)
return future
def done(self, result=None):
self._result = result
while self._callbacks:
function, args, kwargs, future = 
self._callbacks.pop()
func_result = function(
result, *args, **kwargs)
future.done(func_result)
def callback1(result):
print('Callback 1 gets:', result)
return 'callback1_result'
def callback2(result):
print('Callback 2 gets:', result)
return 'callback2_result'
def callback_n(result, n=1):
print('Callback {} gets:'.format(n), result)
return 'callback_n_result'
future = Future()
new_future = future.add_callback(callback1)
.add_callback(callback2)
future.done('Initial data')
new_future.add_callback(callback_n, n=3)
Callback 1 gets: Initial data
Callback 2 gets: callback1_result
Callback 3 gets: callback2_result
The Future is here – Promise in JavaScript
/* A function that returns a promise */
function readFile(filename, enc){
return new Promise(function (fulfill, reject){
fs.readFile(filename, enc, function (err, res){
if (err) reject(err);
else fulfill(res);
});
});
}
/* Adding callbacks */
readFile(filename, 'utf8').then(
function (res){
alert('Done: ' + res);
},
function (reason){
alert('Error: ' + reason);
}
);
readFile(filename, 'utf8').then(...).then(...).then(...);
The Future is here – Deferred in Twisted
from twisted.internet import defer
def get_data():
d = defer.Deferred()
d.callback(3)
return d
def print_result(res):
print res
raise AssertionError('Catch me!')
def handle_exception(failure):
failure.trap(AssertionError)
sys.stderr.write(str(failure))
d = get_data()
d.addCallback(print_data)
d.addErrback(handle_exception)
The Future is here – Future in asyncio
(not to be confused with concurrent.futures.Future)
import asyncio
def get_data():
future = asyncio.Future()
future.set_result('Future is done!')
return future
def print_result(future):
print(future.result())
loop.stop()
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(get_data())
future.add_done_callback(print_result)
try:
loop.run_forever()
finally:
loop.close()
The Future is here
Problems
• Spaghetti code.
• The execution flow is not clear.
• Errors handling is harder.
https://xkcd.com/338/
Part 4 – Await asynchronously.
Await asynchronously – General coroutine
def coroutine(data):
print('Passed 1:', data)
res1 = yield data + 1
print('Passed 2:', res1)
res2 = yield res1 + 1
print('Passed 3:', res2)
Passed 1: 1
Got 1: 2
Passed 2: 20
Got 2: 21
cor = coroutine(1)
val1 = next(cor)
print('Got 1:', val1)
val2= cor.send(val1 * 10)
print('Got 2:', val2)
Await asynchronously – General coroutine
def coroutine(data):
print('Passed 1:', data)
res1 = yield data + 1
print('Passed 2:', res1)
yield res1 + 1
class Coroutine:
def __init__(self, data):
self._data = data
self._state = 0
def __next__(self):
self.send(None)
def send(self, res):
if self._state == 0:
if res is not None:
raise TypeError(
"can't send non-None value to "
"a just-started generator")
print('Passed 1:', self._data)
return self._data + 1
elif self._state == 1:
print('Passed 2:', res)
return res + 1
else:
raise StopIteration
self._state += 1
Await asynchronously – General asyncio coroutine
@coroutine
def my_coroutine(*args, **kwargs):
future1 = run_some_coroutine()
res1 = yield future1
print("First result:", res1)
res2 = yield run_some_coroutine(res1)
print("Second result:", res2)
return res2 + 1
res_future = my_coroutine()
loop = asyncio.get_event_loop()
loop.run_until_complete(res_future)
print('Total result', res_future.result())
First result: 10
Second result: 20
Total result 21
Await asynchronously – General asyncio coroutine
@coroutine
def my_coroutine(*args):
res1 = yield future1
res2 = yield future2
return res2
res_future = my_coroutine()
print(res_future.result())
def coroutine(func):
def outer(*args, **kwargs):
cor = func(*args, **kwargs)
future1 = next(cor)
res_future = asyncio.Future()
future1.add_done_callback(
partial(rewind_future_callback,
cor=cor,
res_future=res_future))
return res_future
return outer
1
2
3
3
4
Await asynchronously – General asyncio coroutine
@coroutine
def my_coroutine(*args):
res1 = yield future1
res2 = yield future2
return res2
res_future = my_coroutine()
print(res_future.result())
def rewind_future_callback(
future1, cor, res_future):
res1 = future1.result()
try:
coroutine_result = cor.send(res1)
except StopIteration as ex:
res_future.set_result(ex.value)
else:
coroutine_result.add_done_callback(
partial(rewind_future_callback,
cor=cor,
res_future=res_future))
1
2
3
4
Await asynchronously – General asyncio coroutine
@coroutine
def my_coroutine(*args):
res1 = yield from future1
res2 = yield from future2
return res2
async def my_coroutine(*args):
res1 = await future1
res2 = await future2
return res2
Await asynchronously – Some rules
async def my_coroutine(*args):
res = await get_data()
1. Use async def to create a coroutine.
2. Use await to get real data from a
future, coroutine or a task.
async def do_stuff():
try:
return await moar_stuff()
except SomeException:
return None
3. Handle exceptions as usual.
class ClassWithCoroutines:
def __init__(self, loop):
self._loop = loop
4. Keep your loop around.
async with asyncfile() as file:
async for line in file:
print(line)
5. Use async with and async for. They
are awesome.
Thank you!

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017
 
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While TestingQA Fest 2019. Saar Rachamim. Developing Tools, While Testing
QA Fest 2019. Saar Rachamim. Developing Tools, While Testing
 
Abusing text/template for data transformation
Abusing text/template for data transformationAbusing text/template for data transformation
Abusing text/template for data transformation
 
Binomial heap
Binomial heapBinomial heap
Binomial heap
 
Go for the paranoid network programmer
Go for the paranoid network programmerGo for the paranoid network programmer
Go for the paranoid network programmer
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful wedding
 
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
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲーム
 
The Ring programming language version 1.5.2 book - Part 74 of 181
The Ring programming language version 1.5.2 book - Part 74 of 181The Ring programming language version 1.5.2 book - Part 74 of 181
The Ring programming language version 1.5.2 book - Part 74 of 181
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in Elixir
 
PyconKR 2018 Deep dive into Coroutine
PyconKR 2018 Deep dive into CoroutinePyconKR 2018 Deep dive into Coroutine
PyconKR 2018 Deep dive into Coroutine
 
201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian
 
Fia fabila
Fia fabilaFia fabila
Fia fabila
 
Tugas 2
Tugas 2Tugas 2
Tugas 2
 
Workflow && t1k
Workflow && t1kWorkflow && t1k
Workflow && t1k
 
Ds 2 cycle
Ds 2 cycleDs 2 cycle
Ds 2 cycle
 
LvivPy4 - Threading vs asyncio
LvivPy4 - Threading vs asyncioLvivPy4 - Threading vs asyncio
LvivPy4 - Threading vs asyncio
 
C++ practical
C++ practicalC++ practical
C++ practical
 
"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014
 
Introducción a Elixir
Introducción a ElixirIntroducción a Elixir
Introducción a Elixir
 

Andere mochten auch

North star 2011 proposed event
North star 2011 proposed eventNorth star 2011 proposed event
North star 2011 proposed event
Eric Ang Tze Chuen
 
Evoluzione ed applicazione dell'iniziativa Minder nella pratica
Evoluzione ed applicazione dell'iniziativa Minder nella praticaEvoluzione ed applicazione dell'iniziativa Minder nella pratica
Evoluzione ed applicazione dell'iniziativa Minder nella pratica
Michele Bettini
 
Minha Petição de Refúgio à ACNUR
Minha Petição de Refúgio à ACNURMinha Petição de Refúgio à ACNUR
Minha Petição de Refúgio à ACNUR
Ricardo Rodrigues
 
Express Reporting and Financial Inclusion Analytics
Express Reporting and Financial Inclusion Analytics Express Reporting and Financial Inclusion Analytics
Express Reporting and Financial Inclusion Analytics
MIX
 

Andere mochten auch (17)

A Gentle Introduction to Event Loops
A Gentle Introduction to Event LoopsA Gentle Introduction to Event Loops
A Gentle Introduction to Event Loops
 
Introduction to asyncio
Introduction to asyncioIntroduction to asyncio
Introduction to asyncio
 
North star 2011 proposed event
North star 2011 proposed eventNorth star 2011 proposed event
North star 2011 proposed event
 
civil eng diploma1
civil eng diploma1civil eng diploma1
civil eng diploma1
 
Taneiqua Cobb
Taneiqua CobbTaneiqua Cobb
Taneiqua Cobb
 
Barclay Jones Recruiters Write Great Job Adverts Webinar
Barclay Jones Recruiters Write Great Job Adverts WebinarBarclay Jones Recruiters Write Great Job Adverts Webinar
Barclay Jones Recruiters Write Great Job Adverts Webinar
 
scan0002
scan0002scan0002
scan0002
 
lifeWay_logo
lifeWay_logolifeWay_logo
lifeWay_logo
 
A Crise da Maioria
A Crise da MaioriaA Crise da Maioria
A Crise da Maioria
 
São Paulo City Tour
São Paulo City TourSão Paulo City Tour
São Paulo City Tour
 
Evoluzione ed applicazione dell'iniziativa Minder nella pratica
Evoluzione ed applicazione dell'iniziativa Minder nella praticaEvoluzione ed applicazione dell'iniziativa Minder nella pratica
Evoluzione ed applicazione dell'iniziativa Minder nella pratica
 
Minha Petição de Refúgio à ACNUR
Minha Petição de Refúgio à ACNURMinha Petição de Refúgio à ACNUR
Minha Petição de Refúgio à ACNUR
 
O que você precisa saber para investir em Renda Variável !
O que você precisa saber para investir em Renda Variável ! O que você precisa saber para investir em Renda Variável !
O que você precisa saber para investir em Renda Variável !
 
Express Reporting and Financial Inclusion Analytics
Express Reporting and Financial Inclusion Analytics Express Reporting and Financial Inclusion Analytics
Express Reporting and Financial Inclusion Analytics
 
Remotee
RemoteeRemotee
Remotee
 
Решение окружного суда Северной Калифорнии
Решение окружного суда Северной КалифорнииРешение окружного суда Северной Калифорнии
Решение окружного суда Северной Калифорнии
 
Types of parallelism
Types of parallelismTypes of parallelism
Types of parallelism
 

Ähnlich wie Introducing to Asynchronous Programming

Gevent what's the point
Gevent what's the pointGevent what's the point
Gevent what's the point
seanmcq
 
how to reuse code
how to reuse codehow to reuse code
how to reuse code
jleed1
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
priestmanmable
 

Ähnlich wie Introducing to Asynchronous Programming (20)

EcmaScript 6
EcmaScript 6 EcmaScript 6
EcmaScript 6
 
Giorgio zoppi cpp11concurrency
Giorgio zoppi cpp11concurrencyGiorgio zoppi cpp11concurrency
Giorgio zoppi cpp11concurrency
 
Gevent be or not to be
Gevent be or not to beGevent be or not to be
Gevent be or not to be
 
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
«Gevent — быть или не быть?» Александр Мокров, Positive Technologies
 
Gevent what's the point
Gevent what's the pointGevent what's the point
Gevent what's the point
 
Gevent rabbit rpc
Gevent rabbit rpcGevent rabbit rpc
Gevent rabbit rpc
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Node.js System: The Landing
Node.js System: The LandingNode.js System: The Landing
Node.js System: The Landing
 
GenServer in action
GenServer in actionGenServer in action
GenServer in action
 
GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev   GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev
 
how to reuse code
how to reuse codehow to reuse code
how to reuse code
 
ES6 generators
ES6 generatorsES6 generators
ES6 generators
 
Node js
Node jsNode js
Node js
 
Javascript
JavascriptJavascript
Javascript
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
 
CoffeeScript
CoffeeScriptCoffeeScript
CoffeeScript
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Advanced JavaScript
Advanced JavaScript Advanced JavaScript
Advanced JavaScript
 
Python decorators (中文)
Python decorators (中文)Python decorators (中文)
Python decorators (中文)
 
III MCS python lab (1).pdf
III MCS python lab (1).pdfIII MCS python lab (1).pdf
III MCS python lab (1).pdf
 

Kürzlich hochgeladen

Spellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please PractiseSpellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please Practise
AnaAcapella
 
1029 - Danh muc Sach Giao Khoa 10 . pdf
1029 -  Danh muc Sach Giao Khoa 10 . pdf1029 -  Danh muc Sach Giao Khoa 10 . pdf
1029 - Danh muc Sach Giao Khoa 10 . pdf
QucHHunhnh
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdf
QucHHunhnh
 

Kürzlich hochgeladen (20)

Spatium Project Simulation student brief
Spatium Project Simulation student briefSpatium Project Simulation student brief
Spatium Project Simulation student brief
 
Asian American Pacific Islander Month DDSD 2024.pptx
Asian American Pacific Islander Month DDSD 2024.pptxAsian American Pacific Islander Month DDSD 2024.pptx
Asian American Pacific Islander Month DDSD 2024.pptx
 
psychiatric nursing HISTORY COLLECTION .docx
psychiatric  nursing HISTORY  COLLECTION  .docxpsychiatric  nursing HISTORY  COLLECTION  .docx
psychiatric nursing HISTORY COLLECTION .docx
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan Fellows
 
Magic bus Group work1and 2 (Team 3).pptx
Magic bus Group work1and 2 (Team 3).pptxMagic bus Group work1and 2 (Team 3).pptx
Magic bus Group work1and 2 (Team 3).pptx
 
Micro-Scholarship, What it is, How can it help me.pdf
Micro-Scholarship, What it is, How can it help me.pdfMicro-Scholarship, What it is, How can it help me.pdf
Micro-Scholarship, What it is, How can it help me.pdf
 
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
 
How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17
 
How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17
 
Spellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please PractiseSpellings Wk 3 English CAPS CARES Please Practise
Spellings Wk 3 English CAPS CARES Please Practise
 
ComPTIA Overview | Comptia Security+ Book SY0-701
ComPTIA Overview | Comptia Security+ Book SY0-701ComPTIA Overview | Comptia Security+ Book SY0-701
ComPTIA Overview | Comptia Security+ Book SY0-701
 
1029 - Danh muc Sach Giao Khoa 10 . pdf
1029 -  Danh muc Sach Giao Khoa 10 . pdf1029 -  Danh muc Sach Giao Khoa 10 . pdf
1029 - Danh muc Sach Giao Khoa 10 . pdf
 
microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introduction
 
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptxBasic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
 
Unit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptxUnit-IV- Pharma. Marketing Channels.pptx
Unit-IV- Pharma. Marketing Channels.pptx
 
Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024
 
Unit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxUnit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptx
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdf
 
Understanding Accommodations and Modifications
Understanding  Accommodations and ModificationsUnderstanding  Accommodations and Modifications
Understanding Accommodations and Modifications
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 

Introducing to Asynchronous Programming

  • 2. Oleksandr Fedorov • Software Engineer. • More than 5 years in Python. • 1.5 years of QA Automation. E-mail: a.g.fedorof@gmail.com Skype ID: a.g.fedorof
  • 3. Agenda 1. The evolution of a loop. 2. We will call you back. 3. The Future is here. 4. Await asynchronously. BDD with Python
  • 4. Part 1 - The evolution of a loop
  • 5. The evolution of a loop from anykey import get_key def loop(): while True: key = get_key() if key is not None: break if __name__ == '__main__': loop()
  • 6. The evolution of a loop Tasks: 183 total, 2 running, 181 sleeping, 0 stopped, 0 zombie PID USER PR NI SHR S %CPU %MEM TIME+ COMMAND 1949 alex 20 0 4408 R 99,7 0,1 0:29.94 python 1602 alex 20 0 28484 S 3,7 1,2 6:20.05 Viber 29713 alex 20 0 79952 S 2,0 1,9 1:41.21 skype 640 root 20 0 23980 S 1,3 0,4 2:29.21 Xorg
  • 7. The evolution of a loop import time from anykey import get_key def loop(): while True: key = get_key() if key is not None: break time.sleep(0.5) if __name__ == '__main__': loop()
  • 8. The evolution of a loop – `select` example. # twisted/internet/selectreactor.py # class SelectReactor... Kinda of. def doSelect(self, timeout): r, w, ignored = _select(self._reads, self._writes, [], timeout) for selectables, method in ((r, "doRead"), (w, "doWrite")): for selectable in selectables: self._doReadOrWrite(selectable, method)
  • 9. The evolution of a loop. I/O loops. # Our example loop() # Twisted from twisted.internet import reactor reactor.run() # Tornado import tornado.ioloop tornado.ioloop.IOLoop.current().start() # pygame while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() pygame.display.flip() # Tkinter App().mainloop() # Asyncio import asyncio asyncio.get_event_loop().run_forever() # JavaScript /* Nothing to do, it already runs */
  • 10.
  • 11. Part 2 – We will call you back
  • 12. We will call you back def loop(): while True: key = get_key() if key == 'q': break if __name__ == '__main__': loop()
  • 13. We will call you back def loop(): while True: key = get_key() if key == 'a': go_left() elif key == 'b': ... elif key == 'c': ... elif key == 'q': break if __name__ == '__main__': loop() def loop(callbacks): while True: key = get_key() if key in callbacks: callbacks[key]() elif key == 'q': break if __name__ == '__main__': loop({ 'a': go_left, 'b': ..., 'c': ..., })
  • 14. We will call you back - jQuery $.ajax({ url: "page.html", success: function(){ alert("done"); } }); $.ajax({ statusCode: { 404: function() { alert( "page not found" ); } } });
  • 15. We will call you back - Tkinter import tkinter as tk class Application(tk.Frame): def __init__(self, master=None): ... self.createWidgets() def createWidgets(self): self.hi_there = tk.Button(self) self.hi_there["text"] = "click me" self.hi_there["command"] = self.say_hi self.QUIT = tk.Button(self, text="QUIT", fg="red", command=root.destroy) def say_hi(self): print("hi there, everyone!") root = tk.Tk() app = Application(master=root) app.mainloop()
  • 16.
  • 17. Part 3 – The Future is here
  • 18. The Future is here Future (aka Deferred, aka Promise) • Composite of callbacks. • Callbacks can be added in both "pending" and "done" states. • The result passed to a future is propagated to its callbacks. • It's possible to propagate errors (exceptions).
  • 19. The Future is here – Simple example class Future: _nope = object() def __init__(self): self._callbacks = [] self._result = self._nope def add_callback(self, function, *args, **kwargs): future = Future() self._callbacks.append( (function, args, kwargs, future)) if self._result != self._nope: self.done(self._result) return future def done(self, result=None): self._result = result while self._callbacks: function, args, kwargs, future = self._callbacks.pop() func_result = function( result, *args, **kwargs) future.done(func_result) def callback1(result): print('Callback 1 gets:', result) return 'callback1_result' def callback2(result): print('Callback 2 gets:', result) return 'callback2_result' def callback_n(result, n=1): print('Callback {} gets:'.format(n), result) return 'callback_n_result' future = Future() new_future = future.add_callback(callback1) .add_callback(callback2) future.done('Initial data') new_future.add_callback(callback_n, n=3) Callback 1 gets: Initial data Callback 2 gets: callback1_result Callback 3 gets: callback2_result
  • 20. The Future is here – Promise in JavaScript /* A function that returns a promise */ function readFile(filename, enc){ return new Promise(function (fulfill, reject){ fs.readFile(filename, enc, function (err, res){ if (err) reject(err); else fulfill(res); }); }); } /* Adding callbacks */ readFile(filename, 'utf8').then( function (res){ alert('Done: ' + res); }, function (reason){ alert('Error: ' + reason); } ); readFile(filename, 'utf8').then(...).then(...).then(...);
  • 21. The Future is here – Deferred in Twisted from twisted.internet import defer def get_data(): d = defer.Deferred() d.callback(3) return d def print_result(res): print res raise AssertionError('Catch me!') def handle_exception(failure): failure.trap(AssertionError) sys.stderr.write(str(failure)) d = get_data() d.addCallback(print_data) d.addErrback(handle_exception)
  • 22. The Future is here – Future in asyncio (not to be confused with concurrent.futures.Future) import asyncio def get_data(): future = asyncio.Future() future.set_result('Future is done!') return future def print_result(future): print(future.result()) loop.stop() loop = asyncio.get_event_loop() future = asyncio.ensure_future(get_data()) future.add_done_callback(print_result) try: loop.run_forever() finally: loop.close()
  • 23. The Future is here Problems • Spaghetti code. • The execution flow is not clear. • Errors handling is harder.
  • 25. Part 4 – Await asynchronously.
  • 26. Await asynchronously – General coroutine def coroutine(data): print('Passed 1:', data) res1 = yield data + 1 print('Passed 2:', res1) res2 = yield res1 + 1 print('Passed 3:', res2) Passed 1: 1 Got 1: 2 Passed 2: 20 Got 2: 21 cor = coroutine(1) val1 = next(cor) print('Got 1:', val1) val2= cor.send(val1 * 10) print('Got 2:', val2)
  • 27. Await asynchronously – General coroutine def coroutine(data): print('Passed 1:', data) res1 = yield data + 1 print('Passed 2:', res1) yield res1 + 1 class Coroutine: def __init__(self, data): self._data = data self._state = 0 def __next__(self): self.send(None) def send(self, res): if self._state == 0: if res is not None: raise TypeError( "can't send non-None value to " "a just-started generator") print('Passed 1:', self._data) return self._data + 1 elif self._state == 1: print('Passed 2:', res) return res + 1 else: raise StopIteration self._state += 1
  • 28. Await asynchronously – General asyncio coroutine @coroutine def my_coroutine(*args, **kwargs): future1 = run_some_coroutine() res1 = yield future1 print("First result:", res1) res2 = yield run_some_coroutine(res1) print("Second result:", res2) return res2 + 1 res_future = my_coroutine() loop = asyncio.get_event_loop() loop.run_until_complete(res_future) print('Total result', res_future.result()) First result: 10 Second result: 20 Total result 21
  • 29. Await asynchronously – General asyncio coroutine @coroutine def my_coroutine(*args): res1 = yield future1 res2 = yield future2 return res2 res_future = my_coroutine() print(res_future.result()) def coroutine(func): def outer(*args, **kwargs): cor = func(*args, **kwargs) future1 = next(cor) res_future = asyncio.Future() future1.add_done_callback( partial(rewind_future_callback, cor=cor, res_future=res_future)) return res_future return outer 1 2 3 3 4
  • 30. Await asynchronously – General asyncio coroutine @coroutine def my_coroutine(*args): res1 = yield future1 res2 = yield future2 return res2 res_future = my_coroutine() print(res_future.result()) def rewind_future_callback( future1, cor, res_future): res1 = future1.result() try: coroutine_result = cor.send(res1) except StopIteration as ex: res_future.set_result(ex.value) else: coroutine_result.add_done_callback( partial(rewind_future_callback, cor=cor, res_future=res_future)) 1 2 3 4
  • 31. Await asynchronously – General asyncio coroutine @coroutine def my_coroutine(*args): res1 = yield from future1 res2 = yield from future2 return res2 async def my_coroutine(*args): res1 = await future1 res2 = await future2 return res2
  • 32. Await asynchronously – Some rules async def my_coroutine(*args): res = await get_data() 1. Use async def to create a coroutine. 2. Use await to get real data from a future, coroutine or a task. async def do_stuff(): try: return await moar_stuff() except SomeException: return None 3. Handle exceptions as usual. class ClassWithCoroutines: def __init__(self, loop): self._loop = loop 4. Keep your loop around. async with asyncfile() as file: async for line in file: print(line) 5. Use async with and async for. They are awesome.