Bounds
To know if multithreading can speed up a task, one should know the types of bounds that are saturated:
-
CPU-bound (e.g. calculation) -> Python: multithreading doesn’t work (because of the GIL), multiprocessing is the workaround / C++: multithreading works
-
I/O-bound (e.g. accessing files using an external system) -> concurrency (async or multithreading) helps
-
memory-bound (RAM, e.g. copying data)
-
other types of bounds (less common)
Python multiprocessing
In Python, the 2 main ways to do multiprocessing is to use:
multiprocessing: more control over processes
concurrent.futures: for simple parallelism (uses multiprocessing under the hood)
When using multiprocessing with the spawn start method (default on Windows and macOS), processes start a fresh Python instance that imports the main (highest-level) module. Therefore any top-level code (like creating a ProcessPoolExecutor or calling .map()) would be re-executed in each process , potentially causing recursive process creation. Using if name == “main”: prevents those side effects from running in child processes.
# No guard => spawn problem!
# --------- using multiprocessing
from multiprocessing import Process
def work(x):
print(x * x)
p = Process(target=work, args=(5,))
p.start()
p.join()
# --------- using concurrent.futures
from concurrent.futures import ProcessPoolExecutor
def work(x):
return x * x
executor = ProcessPoolExecutor()
results = executor.map(work, range(4))
print(list(results))
In the above script (no guard), on spawn-based platforms (Windows/Mac), when workers start (typically at .map step) they re-run top-level code, so they will create new executors again. This can cause recursive spawning (effectively “infinite” processes).
Start
Use std::thread t1(do_something);
.detach(): let run the thread in the background independently. Ideally stated right after starting the thread.
Finish
.join(): used to wait for a thread to finish. Note: we say “join” because the thread finishes in joining others e.g. it finishes in joining the main thread (example below).
int main() {
std::thread t(do_something);
t.join();
}