self.who()
@sanjioh
I work with computers!
Backend Developer and DevOps Engineer
@MailUp
self.who()
@sanjioh
I work with computers!
Backend Developer and DevOps Engineer
@MailUp
My hobby is computers.
And travelling.
But, computers! <3
PARALLELISM
concurrency with tasks executed simultaneously, literally at the same physical instant
THREAD
part of a process (shares code and memory)
the smallest sequence of instructions that can be managed independently by the OS scheduler (e.g. runnable on a CPU core)
# python3
import requests
_WEBSITES = ('https://www.google.com', 'https://www.amazon.com',
'https://www.facebook.com')
def get_homepages():
homepages = {}
for website in _WEBSITES:
response = requests.get(website)
homepages[website] = response.text
return homepages
if __name__ == '__main__':
homepages = get_homepages()
for website in _WEBSITES:
print(homepages[website])
# python3
import threading
import requests
_WEBSITES = ('https://www.google.com', 'https://www.amazon.com',
'https://www.facebook.com')
def _fetch(website, homepages):
response = requests.get(website)
homepages[website] = response.text # !!!
def get_homepages():
homepages = {}
threads = [threading.Thread(target=_fetch, args=(website, homepages))
for website in _WEBSITES]
for thread in threads: thread.start()
for thread in threads: thread.join()
return homepages
if __name__ == '__main__':
homepages = get_homepages()
for website in _WEBSITES: print(homepages[website])
multiple threads within one process
multiple threads within one process
...executing at the very same time
multiple threads within one process
...executing at the very same time
...on one or more CPU cores
multiple threads within one process
...executing at the very same time
...on one or more CPU cores
...communicating by resource sharing
(most notably: memory)
multiple threads within one process
...executing at the very same time
...on one or more CPU cores
...communicating by resource sharing
(most notably: memory)
...with no control over scheduling by the developer
multithreading programming is...
multithreading programming is...
multithreading programming is...
multithreading programming is...
multithreading programming is...
same applies to multiprocessing
multithreading programming is...
same applies to multiprocessing
"who's there?"
"race condition"
"knock, knock"
"In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once."
https://wiki.python.org/moin/GlobalInterpreterLock
"The GIL is controversial because it prevents multithreaded CPython programs from taking full advantage of multiprocessor systems in certain situations."
Removing Python's GIL: The Gilectomy
https://www.youtube.com/watch?v=P3AyI_u66Bw
by Larry Hastings, core CPython committer
-- photo by Kenneth Reitz
single-threaded synchronous is not concurrent :(
multithreading is OMG NOPE!
do we really need to choose between
poor performance
and
programming pain?
non-blocking sockets
non-blocking sockets
a socket polling method
non-blocking sockets
a socket polling method
a loop
socket.setblocking(False)
select()
epoll()
kqueue()
select()
epoll()
kqueue()
import select
well, it's a loop
nothing fancy to see here
while True: do_stuff()
import select
# sockets = [...]
# def do_reads(socks): ...
# def do_writes(socks): ...
while sockets:
r_sockets, w_sockets, _ = select.select(sockets, sockets, [])
closed_r_sockets = do_reads(r_sockets)
closed_w_sockets = do_writes(w_sockets)
for sock in closed_r_sockets + closed_w_sockets:
sockets.remove(sock)
Twisted solves C10K on a common laptop
Twisted solves C10K on a common laptop
compare this with a threaded implementation:
assuming 128KB/thread of stack size,
~1.3GB memory overhead
(let alone the required context switching)
# python3
from twisted.internet import reactor
reactor.run()
# absolutely nothing happens
# python3
from twisted.internet import reactor
reactor.run()
# absolutely nothing happens
# python3
from twisted.internet import reactor
reactor.run()
# absolutely nothing happens
# python3
from twisted.internet import reactor
reactor.run()
# absolutely nothing happens
# python3
from twisted.internet import reactor
def hello():
print('I like turtles')
reactor.callWhenRunning(hello)
print('Starting the reactor')
reactor.run()
# Starting the reactor
# I like turtles
# python3
from twisted.internet import reactor
def hello():
print('I like turtles')
def stop():
reactor.stop()
reactor.callWhenRunning(hello)
reactor.callWhenRunning(stop)
print('Starting the reactor')
reactor.run()
print('Reactor stopped')
# Starting the reactor
# I like turtles
# Reactor stopped
since these programs don't use sockets at all, why don't they get blocked in the
select()
call?
since these programs don't use sockets at all, why don't they get blocked in the
select()
call?
since these programs don't use sockets at all, why don't they get blocked in the
select()
call?
*more accurately, file descriptors
# python3
from twisted.internet import reactor
def error():
raise Exception('BOOM!')
def back():
print('Aaaand we are back!')
reactor.stop()
reactor.callWhenRunning(error)
reactor.callWhenRunning(back)
print('Starting the reactor')
reactor.run()
# Starting the reactor
# Unhandled Error
# Traceback (most recent call last):
# ...
# builtins.Exception: BOOM!
# Aaaand we are back!
WE: "Reactor, please, do_this_thing(), it's important"
R: "Sure"
WE: "Uhm, let me know when it's done.
Please callback() ASAP"
R: "You bet"
WE: "Oh, and Reactor...should anything go wrong...
make sure you errback() to me"
R: "Gotcha"
WE: <3
R: <3
deferred.callback(result)
deferred.errback(exception)
deferred.callback(result)
deferred.errback(exception)
# python3
from twisted.internet.defer import Deferred
def eb(error):
print('OMG NOOO!')
print(error)
def cb(result):
print('WHOA, NICE!')
print(result)
d = Deferred()
d.addCallbacks(cb, eb)
d.callback(42) # fire!
# WHOA, NICE!
# 42
# python3
from twisted.internet.defer import Deferred
def eb(error):
print('OMG NOOO!')
print(error)
def cb(result):
print('WHOA, NICE!')
print(result)
d = Deferred()
d.addCallbacks(cb, eb)
d.errback(Exception('BOOM!')) # fire!
# OMG NOOO!
# [Failure instance: Traceback (failure with no frames): <class 'Exception'>: BOOM!
# ]
from twisted.internet.defer import Deferred
def stage0_cb(result): print('What is love?'); raise Exception
def stage0_eb(error): print('guh')
def stage1_cb(result): print('blablabla')
def stage1_eb(error): print("Baby don't hurt me"); raise Exception
def stage2_cb(result): print('Eeeeh Macarena!')
def stage2_eb(error): print("Don't hurt me"); return 'No more'
def stage3_cb(result): print(result)
def stage3_eb(error): print("I'm blue dabadi dabada")
d = Deferred()
d.addCallbacks(stage0_cb, stage0_eb)
d.addCallbacks(stage1_cb, stage1_eb)
d.addCallbacks(stage2_cb, stage2_eb)
d.addCallbacks(stage3_cb, stage3_eb)
d.callback(None)
# What is love?
# Baby don't hurt me
# Don't hurt me
# No more
# python3
from twisted.internet.defer import gatherResults
from twisted.internet import reactor
import treq
_WEBSITES = ('https://www.google.com', 'https://www.amazon.com',
'https://www.facebook.com')
def _print_all(_, homepages):
for website in _WEBSITES: print(homepages[website])
def _store(html, website, homepages):
homepages[website] = html
def get_homepages():
homepages, responses = {}, []
for website in _WEBSITES:
d = treq.get(website)
d.addCallback(treq.content)
d.addCallback(_store, website, homepages)
responses.append(d)
alldone = gatherResults(responses)
alldone.addCallback(_print_all, homepages)
alldone.addCallback(lambda _: reactor.stop())
if __name__ == '__main__':
reactor.callWhenRunning(get_homepages); reactor.run()
by returning a deferred, an API is telling us that it's asynchronous, and that the result isn't available yet
it will be, eventually,
and we'll get it as soon as the deferred is fired
No. Forget it. There's no silver bullet.
"make it work, make it right, make it fast" -- Kent Beck
"make it work, make it right, make it fast" -- Kent Beck
"make it work, make it right, make it fast" -- Kent Beck
"make it work, make it right, make it fast" -- Kent Beck
"make it work, make it right, make it fast" -- Kent Beck
"make it work, make it right, make it fast" -- Kent Beck
state shared among threads today
may become
state shared among machines
across a network tomorrow
strive for statelessness
be an enemy of the state
https://magic.io/blog/uvloop-blazing-fast-python-networking
or questions.
but mostly, answers.
please.
pssssssst. thank you! <3