Robustifying concurrent.futures, Thomas Moreau

Pôle Systematic Paris-Region
Pôle Systematic Paris-RegionPôle Systematic Paris-Region
Robustifying concurrent.futures
Thomas Moreau - Olivier Grisel
1 / 26
Embarassingly parallel computation in python
using a pool of workers
Three API available:
multiprocessing : rst implementation.
concurrent.futures : reimplementation using multiprocessing
under the hood.
loky : robusti cation of concurrent.futures .
2 / 26
The concurrent.futures API
3 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
fit_model is the function that we want to run
asynchronously.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
Wait for the computation to end and return
the result with f.result .
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
Wait for the computation to end and return
the result with f.result .
The ressources are cleaned up.
The Executor : a worker pool
4 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
fit_model is the function that we want to run
asynchronously.
We instanciate a ThreadPoolExecutor with 4
threads.
A new job is submitted to the Executor .
The Future object future1 holds the state of
the computation.
Wait for the computation to end and return
the result with f.result .
The ressources are cleaned up.
The Executor : a worker pool
Submitting more than one job returns an iterator: executor.map
4 / 26
Blocking methods
f.result(timeout=None)
f.exception(timeout=None)
wait for computations to be done.
The Future object: an asynchronous result state.
States
Future objects hold the state of the asynchronous computations, wich can
be in one of 4 states: Not started, Running, Cancelled and Done
The state of a Future can be checked using f.running, f.cancelled,
f.done .
5 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
from concurrent.futures import ThreadPoolExecutor
def fit_model(params):
# Heavy computation
return model
# Create an executor with 4 threads
with ThreadPoolExecutor(max_workers=4) as executor:
# Submit an asynchronous job and return a Future
future1 = executor.submit(fit_model, param1)
# Submit other job
future2 = executor.submit(fit_model, param2)
# Run other computation
...
# Blocking call, wait and return the result
model1 = future1.result(timeout=None)
model2 = future2.result(timeout=None)
# The ressources have been cleaned up
print(model1, model2)
The Executor : a worker pool
6 / 26
Choosing the type of worker: Thread or
Process ?
7 / 26
Running on multiple cores
Python GIL
The internal implementation of python interpreter relies on a "Global
Interpreter Lock" (GIL), protecting the concurrent access to python objects:
Only one thread can acquire it.
Not designed for e cient multicore computing.
Global lock everytime we access a python object.
Released when performing long I/O operations or by some libraries.
(e.g. numpy, openMP,..) 8 / 26
Real system thread:
pthread
windows thread
All the computation are done
with a single interpreter.
Advantages:
Fast spawning
Reduced memory overhead
No communication overhead
(shared python objects)
Thread
9 / 26
Real system thread:
pthread
windows thread
All the computation are done
with a single interpreter.
Advantages:
Fast spawning
Reduced memory overhead
No communication overhead
(shared python objects)
Thread
Wait... shared python objects and a single interpreter?!?
9 / 26
Real system thread:
pthread
windows thread
All the computation are done
with a single interpreter.
Advantages:
Fast spawning
Reduced memory overhead
No communication overhead
(shared python objects)
Thread
Wait... shared python objects and a single interpreter?!?
There is only one GIL!
9 / 26
Thread
Multiple threads running python code:
This is not quicker than sequential even on a multicore machine.
10 / 26
Thread
Threads hold the GIL when running python code.
They release it when blocking for I/O:
Or when using some c library:
11 / 26
Create a new python interpreter
per worker.
Each worker run in its own
interpreter.
Inconvenients:
Slow spawning
Higher memory overhead
Higher communication overhead.
Process
12 / 26
Create a new python interpreter
per worker.
Each worker run in its own
interpreter.
Inconvenients:
Slow spawning
Higher memory overhead
Higher communication overhead.
Process
But there is no GIL!
The computation can be done in parallel even for python code.
12 / 26
Create a new python interpreter
per worker.
Each worker run in its own
interpreter.
Inconvenients:
Slow spawning
Higher memory overhead
Higher communication overhead.
Process
But there is no GIL!
The computation can be done in parallel even for python code.
Method to create a new interpreter: fork or spawn
12 / 26
Advantages:
Low spawning overhead.
The interpreter is warm
imported.
Inconvenient:
Bad interaction with
multithreaded programs
Does not respect the POSIX
speci cations
Launching a new interpreter: fork
Duplicate the current interpreter. (Only available on UNIX)
Some libraries crash: numpy on OSX, openMP, ...⇒
13 / 26
Advantages:
Safe (respect POSIX)
Fresh interpreter without
extra libraries.
Inconvenient:
Slower to start.
Need to reload the libraries,
rede ne the functions...
Launching a new interpreter: spawn
Create a new interpreter from scratch.
14 / 26
Comparison between Thread and Process
Thread Process (fork) Process (spawn)
E cient multicore run
No communication overhead
POSIX safe
No spawning overhead
15 / 26
Comparison between Thread and Process
Thread Process (fork) Process (spawn)
E cient multicore run
No communication overhead
POSIX safe
No spawning overhead
Hide the spawning overhead by reusing the pool of processes.⇒
16 / 26
Reusing a ProcessPoolExecutor .
17 / 26
Reusing a ProcessPoolExecutor .
To Avoid the spawning overhead, reuse a previously started
ProcessPoolExecutor .
The spawning overhead is only paid once.
Easy using a global pool of process.
Main issue: is that robust?
18 / 26
Managing the state of the executor
Example deadlock
>>> from concurrent.futures import ProcessPoolExecutor
>>> with ProcessPoolExecutor(max_workers=4) as e:
... e.submit(lambda: 1).result()
...
Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/queues.py", line 241, in _feed
obj = _ForkingPickler.dumps(obj)
File "/usr/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fcff0184d08>:
attribute lookup <lambda> on __main__ failed
^C
It can be tricky to know which submit call crashed the Executor .
19 / 26
Managing the state of the executor
Example deadlock
>>> from concurrent.futures import ProcessPoolExecutor
>>> with ProcessPoolExecutor(max_workers=4) as e:
... e.submit(lambda: 1)
...
Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/queues.py", line 241, in _feed
obj = _ForkingPickler.dumps(obj)
File "/usr/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7f5c787bd488>:
attribute lookup <lambda> on __main__ failed
^C
Even worse, shutdown itself is deadlocked.
20 / 26
Reusable pool of workers: loky .
21 / 26
loky : a robust pool of workers
>>> from loky import ProcessPoolExecutor
>>> class CrashAtPickle(object):
... """Bad object that triggers a segfault at unpickling time."""
... def __reduce__(self):
... raise RuntimeError()
...
>>> with ProcessPoolExecutor(max_workers=4) as e:
... e.submit(CrashAtPickle()).result()
...
Traceback (most recent call last):
...
RuntimeError
Traceback (most recent call last):
...
BrokenExecutor: The QueueFeederThread was terminated abruptly while feeding a
new job. This can be due to a job pickling error.
>>>
Return and raise a user friendly exception.
Fix some other deadlocks.
22 / 26
>>> from loky import get_reusable_executor
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(id, 42).result()
139655595838272
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(CrashAtUnpickle()).result()
Traceback (most recent call last):
...
BrokenExecutorError
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
1
>>> excutor.submit(id, 42).result()
139655595838272
Create a ProcessPoolExecutor using the
factory function get_reusable_executor .
A reusable ProcessPoolExecutor
23 / 26
>>> from loky import get_reusable_executor
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(id, 42).result()
139655595838272
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(CrashAtUnpickle()).result()
Traceback (most recent call last):
...
BrokenExecutorError
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
1
>>> excutor.submit(id, 42).result()
139655595838272
Create a ProcessPoolExecutor using the
factory function get_reusable_executor .
The executor can be used exactly as
ProcessPoolExecutor .
A reusable ProcessPoolExecutor
23 / 26
>>> from loky import get_reusable_executor
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(id, 42).result()
139655595838272
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(CrashAtUnpickle()).result()
Traceback (most recent call last):
...
BrokenExecutorError
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
1
>>> excutor.submit(id, 42).result()
139655595838272
Create a ProcessPoolExecutor using the
factory function get_reusable_executor .
The executor can be used exactly as
ProcessPoolExecutor .
When the factory is called elsewhere, reuse
the same executor if it is working.
A reusable ProcessPoolExecutor
23 / 26
>>> from loky import get_reusable_executor
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(id, 42).result()
139655595838272
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
0
>>> excutor.submit(CrashAtUnpickle()).result()
Traceback (most recent call last):
...
BrokenExecutorError
>>> excutor = get_reusable_executor(max_workers=4)
>>> print(excutor.executor_id)
1
>>> excutor.submit(id, 42).result()
139655595838272
Create a ProcessPoolExecutor using the
factory function get_reusable_executor .
The executor can be used exactly as
ProcessPoolExecutor .
When the factory is called elsewhere, reuse
the same executor if it is working.
When the executor is broken, automatically
re-spawn a new one.
A reusable ProcessPoolExecutor
23 / 26
Conclusion
24 / 26
Conclusion
Thread can be e cient to run multicore programs if your
code releases the GIL.
Else, you should use Process with spawn and try to reuse the
pool of process as much as possible.
loky can help you do that ;).
Improves the management of a pool of workers in projects
such as joblib .
25 / 26
Thanks for your attention!
Slides available at tommoral.github.io/pyparis17/
More on the GIL by Dave Beazley : dabeaz.com/python/GIL.pdf
Loky project : github.com/tommoral/loky
@tomamoral
26 / 26
1 of 47

Recommended

Inline function(oops) by
Inline function(oops)Inline function(oops)
Inline function(oops)Jay Patel
6K views3 slides
Python Introduction | JNTUA | R19 | UNIT 1 | Functions by
Python Introduction | JNTUA | R19 | UNIT 1 | FunctionsPython Introduction | JNTUA | R19 | UNIT 1 | Functions
Python Introduction | JNTUA | R19 | UNIT 1 | FunctionsFabMinds
58 views9 slides
INLINE FUNCTION IN C++ by
INLINE FUNCTION IN C++INLINE FUNCTION IN C++
INLINE FUNCTION IN C++Vraj Patel
5.9K views13 slides
Inline functions by
Inline functionsInline functions
Inline functionsDhwaniHingorani
157 views7 slides
Inline Functions and Default arguments by
Inline Functions and Default argumentsInline Functions and Default arguments
Inline Functions and Default argumentsNikhil Pandit
6K views10 slides
Inline function in C++ by
Inline function in C++Inline function in C++
Inline function in C++Learn By Watch
2.1K views8 slides

More Related Content

What's hot

User defined functions.1 by
User defined functions.1User defined functions.1
User defined functions.1Mohammad Zuber Vohra
33 views16 slides
Functions in C++ by
Functions in C++Functions in C++
Functions in C++home
3.1K views77 slides
Functions in C++ by
Functions in C++Functions in C++
Functions in C++Nikhil Pandit
1.1K views13 slides
Bca 2nd sem u-4 operator overloading by
Bca 2nd sem u-4 operator overloadingBca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloadingRai University
1.7K views32 slides
Basic information of function in cpu by
Basic information of function in cpuBasic information of function in cpu
Basic information of function in cpuDhaval Jalalpara
142 views15 slides
16717 functions in C++ by
16717 functions in C++16717 functions in C++
16717 functions in C++LPU
4.9K views66 slides

What's hot(20)

Functions in C++ by home
Functions in C++Functions in C++
Functions in C++
home 3.1K views
Bca 2nd sem u-4 operator overloading by Rai University
Bca 2nd sem u-4 operator overloadingBca 2nd sem u-4 operator overloading
Bca 2nd sem u-4 operator overloading
Rai University1.7K views
Basic information of function in cpu by Dhaval Jalalpara
Basic information of function in cpuBasic information of function in cpu
Basic information of function in cpu
Dhaval Jalalpara142 views
16717 functions in C++ by LPU
16717 functions in C++16717 functions in C++
16717 functions in C++
LPU4.9K views
Inline assembly language programs in c by Tech_MX
Inline assembly language programs in cInline assembly language programs in c
Inline assembly language programs in c
Tech_MX7.7K views
Operator overloadng by preethalal
Operator overloadngOperator overloadng
Operator overloadng
preethalal4.8K views
#OOP_D_ITS - 5th - C++ Oop Operator Overloading by Hadziq Fabroyir
#OOP_D_ITS - 5th - C++ Oop Operator Overloading#OOP_D_ITS - 5th - C++ Oop Operator Overloading
#OOP_D_ITS - 5th - C++ Oop Operator Overloading
Hadziq Fabroyir2.4K views
Synapse india complain sharing info on chapter 8 operator overloading by SynapseindiaComplaints
Synapse india complain sharing info on chapter 8   operator overloadingSynapse india complain sharing info on chapter 8   operator overloading
Synapse india complain sharing info on chapter 8 operator overloading
Lecture#6 functions in c++ by NUST Stuff
Lecture#6 functions in c++Lecture#6 functions in c++
Lecture#6 functions in c++
NUST Stuff518 views
Mca 2nd sem u-4 operator overloading by Rai University
Mca 2nd  sem u-4 operator overloadingMca 2nd  sem u-4 operator overloading
Mca 2nd sem u-4 operator overloading
Rai University703 views

Similar to Robustifying concurrent.futures, Thomas Moreau

Effective java item 80 and 81 by
Effective java   item 80 and 81Effective java   item 80 and 81
Effective java item 80 and 81Isaac Liao
136 views28 slides
Parallel Programming With Dot Net by
Parallel Programming With Dot NetParallel Programming With Dot Net
Parallel Programming With Dot NetNeeraj Kaushik
549 views15 slides
What's New In Python 2.5 by
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5Richard Jones
1.7K views74 slides
Concurrent Programming in Java by
Concurrent Programming in JavaConcurrent Programming in Java
Concurrent Programming in JavaRuben Inoto Soto
4.2K views77 slides
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی by
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی Mohammad Reza Kamalifard
424 views15 slides
Chapter 4 by
Chapter 4Chapter 4
Chapter 4temkin abdlkader
505 views44 slides

Similar to Robustifying concurrent.futures, Thomas Moreau(20)

Effective java item 80 and 81 by Isaac Liao
Effective java   item 80 and 81Effective java   item 80 and 81
Effective java item 80 and 81
Isaac Liao136 views
Parallel Programming With Dot Net by Neeraj Kaushik
Parallel Programming With Dot NetParallel Programming With Dot Net
Parallel Programming With Dot Net
Neeraj Kaushik549 views
What's New In Python 2.5 by Richard Jones
What's New In Python 2.5What's New In Python 2.5
What's New In Python 2.5
Richard Jones1.7K views
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی by Mohammad Reza Kamalifard
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی
اسلاید ارائه اول جلسه ۱۰ کلاس پایتون برای هکر های قانونی
Chapter 1. Functions in C++.pdf by TeshaleSiyum
Chapter 1.  Functions in C++.pdfChapter 1.  Functions in C++.pdf
Chapter 1. Functions in C++.pdf
TeshaleSiyum8 views
Chapter_1.__Functions_in_C++[1].pdf by TeshaleSiyum
Chapter_1.__Functions_in_C++[1].pdfChapter_1.__Functions_in_C++[1].pdf
Chapter_1.__Functions_in_C++[1].pdf
TeshaleSiyum1 view
Windows Phone 8 - 3.5 Async Programming by Oliver Scheer
Windows Phone 8 - 3.5 Async ProgrammingWindows Phone 8 - 3.5 Async Programming
Windows Phone 8 - 3.5 Async Programming
Oliver Scheer2.5K views
Using Akka Futures by Knoldus Inc.
Using Akka FuturesUsing Akka Futures
Using Akka Futures
Knoldus Inc.1.5K views
Python testing using mock and pytest by Suraj Deshmukh
Python testing using mock and pytestPython testing using mock and pytest
Python testing using mock and pytest
Suraj Deshmukh5.6K views
Leveraging Completable Futures to handle your query results Asynchrhonously by David Gómez García
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
Lecture 4, c++(complete reference,herbet sheidt)chapter-14 by Abu Saleh
Lecture 4, c++(complete reference,herbet sheidt)chapter-14Lecture 4, c++(complete reference,herbet sheidt)chapter-14
Lecture 4, c++(complete reference,herbet sheidt)chapter-14
Abu Saleh104 views
Bottom of FormCreate your own FunctionFunctionsFor eac.docx by AASTHA76
Bottom of FormCreate your own FunctionFunctionsFor eac.docxBottom of FormCreate your own FunctionFunctionsFor eac.docx
Bottom of FormCreate your own FunctionFunctionsFor eac.docx
AASTHA768 views
Scala Future & Promises by Knoldus Inc.
Scala Future & PromisesScala Future & Promises
Scala Future & Promises
Knoldus Inc.3.3K views
ForLoopandUserDefinedFunctions.pptx by AaliyanShaikh
ForLoopandUserDefinedFunctions.pptxForLoopandUserDefinedFunctions.pptx
ForLoopandUserDefinedFunctions.pptx
AaliyanShaikh3 views

More from Pôle Systematic Paris-Region

OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na... by
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...Pôle Systematic Paris-Region
686 views39 slides
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ... by
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...Pôle Systematic Paris-Region
293 views24 slides
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ... by
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...Pôle Systematic Paris-Region
349 views38 slides
OSIS19_Cloud : Performance and power management in virtualized data centers, ... by
OSIS19_Cloud : Performance and power management in virtualized data centers, ...OSIS19_Cloud : Performance and power management in virtualized data centers, ...
OSIS19_Cloud : Performance and power management in virtualized data centers, ...Pôle Systematic Paris-Region
288 views27 slides
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ... by
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...Pôle Systematic Paris-Region
271 views30 slides
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt... by
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...Pôle Systematic Paris-Region
229 views9 slides

More from Pôle Systematic Paris-Region(20)

Recently uploaded

Perth MeetUp November 2023 by
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023 Michael Price
19 views44 slides
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院 by
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院IttrainingIttraining
41 views8 slides
From chaos to control: Managing migrations and Microsoft 365 with ShareGate! by
From chaos to control: Managing migrations and Microsoft 365 with ShareGate!From chaos to control: Managing migrations and Microsoft 365 with ShareGate!
From chaos to control: Managing migrations and Microsoft 365 with ShareGate!sammart93
9 views39 slides
Five Things You SHOULD Know About Postman by
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About PostmanPostman
30 views43 slides
HTTP headers that make your website go faster - devs.gent November 2023 by
HTTP headers that make your website go faster - devs.gent November 2023HTTP headers that make your website go faster - devs.gent November 2023
HTTP headers that make your website go faster - devs.gent November 2023Thijs Feryn
21 views151 slides
SAP Automation Using Bar Code and FIORI.pdf by
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdfVirendra Rai, PMP
22 views38 slides

Recently uploaded(20)

Perth MeetUp November 2023 by Michael Price
Perth MeetUp November 2023 Perth MeetUp November 2023
Perth MeetUp November 2023
Michael Price19 views
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院 by IttrainingIttraining
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
From chaos to control: Managing migrations and Microsoft 365 with ShareGate! by sammart93
From chaos to control: Managing migrations and Microsoft 365 with ShareGate!From chaos to control: Managing migrations and Microsoft 365 with ShareGate!
From chaos to control: Managing migrations and Microsoft 365 with ShareGate!
sammart939 views
Five Things You SHOULD Know About Postman by Postman
Five Things You SHOULD Know About PostmanFive Things You SHOULD Know About Postman
Five Things You SHOULD Know About Postman
Postman30 views
HTTP headers that make your website go faster - devs.gent November 2023 by Thijs Feryn
HTTP headers that make your website go faster - devs.gent November 2023HTTP headers that make your website go faster - devs.gent November 2023
HTTP headers that make your website go faster - devs.gent November 2023
Thijs Feryn21 views
SAP Automation Using Bar Code and FIORI.pdf by Virendra Rai, PMP
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdf
6g - REPORT.pdf by Liveplex
6g - REPORT.pdf6g - REPORT.pdf
6g - REPORT.pdf
Liveplex10 views
Spesifikasi Lengkap ASUS Vivobook Go 14 by Dot Semarang
Spesifikasi Lengkap ASUS Vivobook Go 14Spesifikasi Lengkap ASUS Vivobook Go 14
Spesifikasi Lengkap ASUS Vivobook Go 14
Dot Semarang37 views
1st parposal presentation.pptx by i238212
1st parposal presentation.pptx1st parposal presentation.pptx
1st parposal presentation.pptx
i2382129 views
Transcript: The Details of Description Techniques tips and tangents on altern... by BookNet Canada
Transcript: The Details of Description Techniques tips and tangents on altern...Transcript: The Details of Description Techniques tips and tangents on altern...
Transcript: The Details of Description Techniques tips and tangents on altern...
BookNet Canada135 views
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by James Anderson
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
James Anderson66 views
Business Analyst Series 2023 - Week 3 Session 5 by DianaGray10
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5
DianaGray10237 views
Piloting & Scaling Successfully With Microsoft Viva by Richard Harbridge
Piloting & Scaling Successfully With Microsoft VivaPiloting & Scaling Successfully With Microsoft Viva
Piloting & Scaling Successfully With Microsoft Viva

Robustifying concurrent.futures, Thomas Moreau

  • 2. Embarassingly parallel computation in python using a pool of workers Three API available: multiprocessing : rst implementation. concurrent.futures : reimplementation using multiprocessing under the hood. loky : robusti cation of concurrent.futures . 2 / 26
  • 4. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model fit_model is the function that we want to run asynchronously. The Executor : a worker pool 4 / 26
  • 5. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. The Executor : a worker pool 4 / 26
  • 6. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. The Executor : a worker pool 4 / 26
  • 7. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. The Executor : a worker pool 4 / 26
  • 8. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. The Executor : a worker pool 4 / 26
  • 9. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. Wait for the computation to end and return the result with f.result . The Executor : a worker pool 4 / 26
  • 10. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. Wait for the computation to end and return the result with f.result . The ressources are cleaned up. The Executor : a worker pool 4 / 26
  • 11. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) fit_model is the function that we want to run asynchronously. We instanciate a ThreadPoolExecutor with 4 threads. A new job is submitted to the Executor . The Future object future1 holds the state of the computation. Wait for the computation to end and return the result with f.result . The ressources are cleaned up. The Executor : a worker pool Submitting more than one job returns an iterator: executor.map 4 / 26
  • 12. Blocking methods f.result(timeout=None) f.exception(timeout=None) wait for computations to be done. The Future object: an asynchronous result state. States Future objects hold the state of the asynchronous computations, wich can be in one of 4 states: Not started, Running, Cancelled and Done The state of a Future can be checked using f.running, f.cancelled, f.done . 5 / 26
  • 13. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 14. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 15. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 16. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 17. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 18. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 19. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 20. from concurrent.futures import ThreadPoolExecutor def fit_model(params): # Heavy computation return model # Create an executor with 4 threads with ThreadPoolExecutor(max_workers=4) as executor: # Submit an asynchronous job and return a Future future1 = executor.submit(fit_model, param1) # Submit other job future2 = executor.submit(fit_model, param2) # Run other computation ... # Blocking call, wait and return the result model1 = future1.result(timeout=None) model2 = future2.result(timeout=None) # The ressources have been cleaned up print(model1, model2) The Executor : a worker pool 6 / 26
  • 21. Choosing the type of worker: Thread or Process ? 7 / 26
  • 22. Running on multiple cores Python GIL The internal implementation of python interpreter relies on a "Global Interpreter Lock" (GIL), protecting the concurrent access to python objects: Only one thread can acquire it. Not designed for e cient multicore computing. Global lock everytime we access a python object. Released when performing long I/O operations or by some libraries. (e.g. numpy, openMP,..) 8 / 26
  • 23. Real system thread: pthread windows thread All the computation are done with a single interpreter. Advantages: Fast spawning Reduced memory overhead No communication overhead (shared python objects) Thread 9 / 26
  • 24. Real system thread: pthread windows thread All the computation are done with a single interpreter. Advantages: Fast spawning Reduced memory overhead No communication overhead (shared python objects) Thread Wait... shared python objects and a single interpreter?!? 9 / 26
  • 25. Real system thread: pthread windows thread All the computation are done with a single interpreter. Advantages: Fast spawning Reduced memory overhead No communication overhead (shared python objects) Thread Wait... shared python objects and a single interpreter?!? There is only one GIL! 9 / 26
  • 26. Thread Multiple threads running python code: This is not quicker than sequential even on a multicore machine. 10 / 26
  • 27. Thread Threads hold the GIL when running python code. They release it when blocking for I/O: Or when using some c library: 11 / 26
  • 28. Create a new python interpreter per worker. Each worker run in its own interpreter. Inconvenients: Slow spawning Higher memory overhead Higher communication overhead. Process 12 / 26
  • 29. Create a new python interpreter per worker. Each worker run in its own interpreter. Inconvenients: Slow spawning Higher memory overhead Higher communication overhead. Process But there is no GIL! The computation can be done in parallel even for python code. 12 / 26
  • 30. Create a new python interpreter per worker. Each worker run in its own interpreter. Inconvenients: Slow spawning Higher memory overhead Higher communication overhead. Process But there is no GIL! The computation can be done in parallel even for python code. Method to create a new interpreter: fork or spawn 12 / 26
  • 31. Advantages: Low spawning overhead. The interpreter is warm imported. Inconvenient: Bad interaction with multithreaded programs Does not respect the POSIX speci cations Launching a new interpreter: fork Duplicate the current interpreter. (Only available on UNIX) Some libraries crash: numpy on OSX, openMP, ...⇒ 13 / 26
  • 32. Advantages: Safe (respect POSIX) Fresh interpreter without extra libraries. Inconvenient: Slower to start. Need to reload the libraries, rede ne the functions... Launching a new interpreter: spawn Create a new interpreter from scratch. 14 / 26
  • 33. Comparison between Thread and Process Thread Process (fork) Process (spawn) E cient multicore run No communication overhead POSIX safe No spawning overhead 15 / 26
  • 34. Comparison between Thread and Process Thread Process (fork) Process (spawn) E cient multicore run No communication overhead POSIX safe No spawning overhead Hide the spawning overhead by reusing the pool of processes.⇒ 16 / 26
  • 36. Reusing a ProcessPoolExecutor . To Avoid the spawning overhead, reuse a previously started ProcessPoolExecutor . The spawning overhead is only paid once. Easy using a global pool of process. Main issue: is that robust? 18 / 26
  • 37. Managing the state of the executor Example deadlock >>> from concurrent.futures import ProcessPoolExecutor >>> with ProcessPoolExecutor(max_workers=4) as e: ... e.submit(lambda: 1).result() ... Traceback (most recent call last): File "/usr/lib/python3.6/multiprocessing/queues.py", line 241, in _feed obj = _ForkingPickler.dumps(obj) File "/usr/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps cls(buf, protocol).dump(obj) _pickle.PicklingError: Can't pickle <function <lambda> at 0x7fcff0184d08>: attribute lookup <lambda> on __main__ failed ^C It can be tricky to know which submit call crashed the Executor . 19 / 26
  • 38. Managing the state of the executor Example deadlock >>> from concurrent.futures import ProcessPoolExecutor >>> with ProcessPoolExecutor(max_workers=4) as e: ... e.submit(lambda: 1) ... Traceback (most recent call last): File "/usr/lib/python3.6/multiprocessing/queues.py", line 241, in _feed obj = _ForkingPickler.dumps(obj) File "/usr/lib/python3.6/multiprocessing/reduction.py", line 51, in dumps cls(buf, protocol).dump(obj) _pickle.PicklingError: Can't pickle <function <lambda> at 0x7f5c787bd488>: attribute lookup <lambda> on __main__ failed ^C Even worse, shutdown itself is deadlocked. 20 / 26
  • 39. Reusable pool of workers: loky . 21 / 26
  • 40. loky : a robust pool of workers >>> from loky import ProcessPoolExecutor >>> class CrashAtPickle(object): ... """Bad object that triggers a segfault at unpickling time.""" ... def __reduce__(self): ... raise RuntimeError() ... >>> with ProcessPoolExecutor(max_workers=4) as e: ... e.submit(CrashAtPickle()).result() ... Traceback (most recent call last): ... RuntimeError Traceback (most recent call last): ... BrokenExecutor: The QueueFeederThread was terminated abruptly while feeding a new job. This can be due to a job pickling error. >>> Return and raise a user friendly exception. Fix some other deadlocks. 22 / 26
  • 41. >>> from loky import get_reusable_executor >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(id, 42).result() 139655595838272 >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(CrashAtUnpickle()).result() Traceback (most recent call last): ... BrokenExecutorError >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 1 >>> excutor.submit(id, 42).result() 139655595838272 Create a ProcessPoolExecutor using the factory function get_reusable_executor . A reusable ProcessPoolExecutor 23 / 26
  • 42. >>> from loky import get_reusable_executor >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(id, 42).result() 139655595838272 >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(CrashAtUnpickle()).result() Traceback (most recent call last): ... BrokenExecutorError >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 1 >>> excutor.submit(id, 42).result() 139655595838272 Create a ProcessPoolExecutor using the factory function get_reusable_executor . The executor can be used exactly as ProcessPoolExecutor . A reusable ProcessPoolExecutor 23 / 26
  • 43. >>> from loky import get_reusable_executor >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(id, 42).result() 139655595838272 >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(CrashAtUnpickle()).result() Traceback (most recent call last): ... BrokenExecutorError >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 1 >>> excutor.submit(id, 42).result() 139655595838272 Create a ProcessPoolExecutor using the factory function get_reusable_executor . The executor can be used exactly as ProcessPoolExecutor . When the factory is called elsewhere, reuse the same executor if it is working. A reusable ProcessPoolExecutor 23 / 26
  • 44. >>> from loky import get_reusable_executor >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(id, 42).result() 139655595838272 >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 0 >>> excutor.submit(CrashAtUnpickle()).result() Traceback (most recent call last): ... BrokenExecutorError >>> excutor = get_reusable_executor(max_workers=4) >>> print(excutor.executor_id) 1 >>> excutor.submit(id, 42).result() 139655595838272 Create a ProcessPoolExecutor using the factory function get_reusable_executor . The executor can be used exactly as ProcessPoolExecutor . When the factory is called elsewhere, reuse the same executor if it is working. When the executor is broken, automatically re-spawn a new one. A reusable ProcessPoolExecutor 23 / 26
  • 46. Conclusion Thread can be e cient to run multicore programs if your code releases the GIL. Else, you should use Process with spawn and try to reuse the pool of process as much as possible. loky can help you do that ;). Improves the management of a pool of workers in projects such as joblib . 25 / 26
  • 47. Thanks for your attention! Slides available at tommoral.github.io/pyparis17/ More on the GIL by Dave Beazley : dabeaz.com/python/GIL.pdf Loky project : github.com/tommoral/loky @tomamoral 26 / 26