🕷️ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 143 (from laksa151)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

📄
INDEXABLE
CRAWLED
15 days ago
🤖
ROBOTS SERVER UNREACHABLE
Failed to connect to robots server: Operation timed out after 2002 milliseconds with 0 bytes received

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.5 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://leimao.github.io/blog/Python-Concurrency-High-Level/
Last Crawled2026-04-07 18:00:34 (15 days ago)
First Indexed2020-08-02 16:54:14 (5 years ago)
HTTP Status Code200
Content
Meta TitleMultiprocessing VS Threading VS AsyncIO in Python - Lei Mao's Log Book
Meta DescriptionUnderstand Python Concurrency from High-Level
Meta Canonicalnull
Boilerpipe Text
Introduction In modern computer programming, concurrency is often required to accelerate solving a problem. In Python programming, we usually have the three library options to achieve concurrency, multiprocessing , threading , and asyncio . Recently, I was aware that as a scripting language Python’s behavior of concurrency has subtle differences compared to the conventional compiled languages such as C/C++. Real Python has already given a good tutorial with code examples on Python concurrency. In this blog post, I would like to discuss the multiprocessing , threading , and asyncio in Python from a high-level, with some additional caveats that the Real Python tutorial has not mentioned. I have also borrowed some good diagrams from their tutorial and the readers should give the credits to them on those illustrations. CPU-Bound VS I/O-Bound The problems that our modern computers are trying to solve could be generally categorized as CPU-bound or I/O-bound. Whether the problem is CPU-bound or I/O-bound affects our selection from the concurrency libraries multiprocessing , threading , and asyncio . Of course, in some scenarios, the algorithm design for solving the problem might change the problem from CPU-bound to I/O-bound or vice versa. The concept of CPU-bound and I/O-bound are universal for all programming languages. CPU-Bound CPU-bound refers to a condition when the time for it to complete the task is determined principally by the speed of the central processor. The faster clock-rate CPU we have, the higher performance of our program will have. Single-Process Single-Thread Synchronous for CPU-Bound Most of single computer programs are CPU-bound. For example, given a list of numbers, computing the sum of all the numbers in the list. I/O-Bound I/O bound refers to a condition when the time it takes to complete a computation is determined principally by the period spent waiting for input/output operations to be completed. This is the opposite of a task being CPU bound. Increasing CPU clock-rate will not increase the performance of our program significantly. On the contrary, if we have faster I/O, such as faster memory I/O, hard drive I/O, network I/O, etc, the performance of our program will boost. Single-Process Single-Thread Synchronous for I/O-Bound Most of the web service related programs are I/O-bound. For example, given a list of restaurant names, finding out their ratings on Yelp. Process VS Thread in Python Process in Python A global interpreter lock (GIL) is a mechanism used in computer-language interpreters to synchronize the execution of threads so that only one native thread can execute at a time. An interpreter that uses GIL always allows exactly one native thread to execute at a time, even if run on a multi-core processor. Note that the native thread here is the number of threads in the physical CPU core, instead of the thread concept in the programming languages. Because Python interpreter uses GIL, a single-process Python program could only use one native thread during execution. That means single-process Python program could not utilize CPU more than 100% (we define the full utilization of a native thread to be 100%) regardless whether it is single-process single-thread or single-process multi-thread. Conventional compiled programming languages, such as C/C++, do not have interpreter, not even mention GIL. Therefore, for a single-process multi-thread C/C++ program, it could utilize many CPU cores and many native threads, and the CPU utilization could be greater than 100%. Therefore, for a CPU-bound task in Python, we would have to write multi-process Python program to maximize its performance. Thread in Python Because a single-process Python could only use one CPU native thread. No matter how many threads were used in a single-process Python program, a single-process multi-thread Python program could only achieve at most 100% CPU utilization. Therefore, for a CPU-bound task in Python, single-process multi-thread Python program would not improve the performance. However, this does not mean multi-thread is useless in Python. For a I/O-bound task in Python, multi-thread could be used to improve the program performance. Multiprocessing VS Threading VS AsyncIO in Python Multiprocessing Using Python multiprocessing , we are able to run a Python using multiple processes. In principle, a multi-process Python program could fully utilize all the CPU cores and native threads available, by creating multiple Python interpreters on many native threads. Because all the processes are independent to each other, and they don’t share memory. To do collaborative tasks in Python using multiprocessing , it requires to use the API provided the operating system. Therefore, there will be slightly large overhead. Multi-Process for CPU-Bound Therefore, for a CPU-bound task in Python, multiprocessing would be a perfect library to use to maximize the performance. Threading Using Python threading , we are able to make better use of the CPU sitting idle when waiting for the I/O. By overlapping the waiting time for requests, we are able to improve the performance. In addition, because all the threads share the same memory, to do collaborative tasks in Python using threading , we would have to be careful and use locks when necessary. Lock and unlock make sure that only one thread could write to memory at one time, but this will also introduce some overhead. Note that the threads we discussed here are different to the native threads in CPU core. The number of native threads in CPU core is usually 2 nowadays, but the number of threads in a single-process Python program could be much larger than 2. Single-Process Multi-Thread for I/O-Bound Therefore, for a I/O-bound task in Python, threading could be a good library candidate to use to maximize the performance. It should also be noted that all the threads are in a pool and there is an executer from the operating system managing the threads deciding who to run and when to run. This can be a short-coming of threading because the operating system actually knows about each thread and can interrupt it at any time to start running a different thread. This is called pre-emptive multitasking since the operating system can pre-empt your thread to make the switch. AsyncIO Given threading is using multi-thread to maximize the performance of a I/O-bound task in Python, we wonder if using multi-thread is necessary. The answer is no, if you know when to switch the tasks. For example, for each thread in a Python program using threading , it will really stay idle between the request is sent and the result is returned. If somehow a thread could know the time I/O request has been sent, it could switch to do another task, without staying idle, and one thread should be sufficient to manage all these tasks. Without the thread management overhead, the execution should be faster for a I/O-bound task. Obviously, threading could not do it, but we have asyncio . Using Python asyncio , we are also able to make better use of the CPU sitting idle when waiting for the I/O. What’s different to threading is that, asyncio is single-process and single-thread. There is an event loop in asyncio which routinely measure the progress of the tasks. If the event loop has measured any progress, it would schedule another task for execution, therefore, minimizing the time spent on waiting I/O. This is also called cooperative multitasking. The tasks must cooperate by announcing when they are ready to be switched out. Single-Process Single-Thread Asynchronous for I/O-Bound The short-coming of asyncio is that the even loop would not know what are the progresses if we don’t tell it. This requires some additional effort when we write the programs using asyncio . Summary Concurrency Type Features Use Criteria Metaphor Multiprocessing Multiple processes, high CPU utilization. CPU-bound We have ten kitchens, ten chefs, ten dishes to cook. Threading Single process, multiple threads, pre-emptive multitasking, OS decides task switching. Fast I/O-bound We have one kitchen, ten chefs, ten dishes to cook. The kitchen is crowded when the ten chefs are present together. AsyncIO Single process, single thread, cooperative multitasking, tasks cooperatively decide switching. Slow I/O-bound We have one kitchen, one chef, ten dishes to cook. Caveats HTOP vs TOP htop would sometimes misinterpret multi-thread Python programs as multi-process programs, as it would show multiple PID s for the Python program. top does not have this problem. On StackOverflow, there is also such a observation . References Speed Up Your Python Program With Concurrency Async Python: The Different Forms of Concurrency
Markdown
[![Lei Mao's Log Book](https://leimao.github.io/images/favicon/android-chrome-512x512.png)](https://leimao.github.io/) [Lei Mao's Log Book](https://leimao.github.io/)[Curriculum](https://leimao.github.io/curriculum)[Blog](https://leimao.github.io/blog)[Articles](https://leimao.github.io/article)[Projects](https://leimao.github.io/project)[Publications](https://leimao.github.io/publication)[Readings](https://leimao.github.io/reading)[Life](https://leimao.github.io/life)[Essay](https://leimao.github.io/essay)[Photography](https://leimao.github.io/photography)[Archives](https://leimao.github.io/archives)[Categories](https://leimao.github.io/categories)[Tags](https://leimao.github.io/tags)[FAQs](https://leimao.github.io/faq) # Multiprocessing VS Threading VS AsyncIO in Python 07-11-2020 07-11-2020 [blog](https://leimao.github.io/blog/) 11 minutes read (About 1666 words) visits ## Introduction In modern computer programming, concurrency is often required to accelerate solving a problem. In Python programming, we usually have the three library options to achieve concurrency, [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html), [`threading`](https://docs.python.org/3/library/threading.html), and [`asyncio`](https://docs.python.org/3/library/asyncio.html). Recently, I was aware that as a scripting language Python’s behavior of concurrency has subtle differences compared to the conventional compiled languages such as C/C++. [Real Python](https://realpython.com/) has already given a good [tutorial](https://realpython.com/python-concurrency/) with [code examples](https://github.com/realpython/materials/tree/master/concurrency-overview) on Python concurrency. In this blog post, I would like to discuss the `multiprocessing`, `threading`, and `asyncio` in Python from a high-level, with some additional caveats that the Real Python tutorial has not mentioned. I have also borrowed some good diagrams from their tutorial and the readers should give the credits to them on those illustrations. ## CPU-Bound VS I/O-Bound The problems that our modern computers are trying to solve could be generally categorized as CPU-bound or I/O-bound. Whether the problem is CPU-bound or I/O-bound affects our selection from the concurrency libraries `multiprocessing`, `threading`, and `asyncio`. Of course, in some scenarios, the algorithm design for solving the problem might change the problem from CPU-bound to I/O-bound or vice versa. The concept of CPU-bound and I/O-bound are universal for all programming languages. ### CPU-Bound CPU-bound refers to a condition when the time for it to complete the task is determined principally by the speed of the central processor. The faster clock-rate CPU we have, the higher performance of our program will have. [![Single-Process Single-Thread Synchronous for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUBound.webp)Single-Process Single-Thread Synchronous for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUBound.webp) Most of single computer programs are CPU-bound. For example, given a list of numbers, computing the sum of all the numbers in the list. ### I/O-Bound I/O bound refers to a condition when the time it takes to complete a computation is determined principally by the period spent waiting for input/output operations to be completed. This is the opposite of a task being CPU bound. Increasing CPU clock-rate will not increase the performance of our program significantly. On the contrary, if we have faster I/O, such as faster memory I/O, hard drive I/O, network I/O, etc, the performance of our program will boost. [![Single-Process Single-Thread Synchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/IOBound.webp)Single-Process Single-Thread Synchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/IOBound.webp) Most of the web service related programs are I/O-bound. For example, given a list of restaurant names, finding out their ratings on Yelp. ## Process VS Thread in Python ### Process in Python A [global interpreter lock](https://en.wikipedia.org/wiki/Global_interpreter_lock) (GIL) is a mechanism used in computer-language interpreters to synchronize the execution of threads so that only one native thread can execute at a time. An interpreter that uses GIL always allows exactly one native thread to execute at a time, even if run on a multi-core processor. Note that the native thread here is the number of threads in the physical CPU core, instead of the thread concept in the programming languages. Because Python interpreter uses GIL, a single-process Python program could only use one native thread during execution. That means single-process Python program could not utilize CPU more than 100% (we define the full utilization of a native thread to be 100%) regardless whether it is single-process single-thread or single-process multi-thread. Conventional compiled programming languages, such as C/C++, do not have interpreter, not even mention GIL. Therefore, for a single-process multi-thread C/C++ program, it could utilize many CPU cores and many native threads, and the CPU utilization could be greater than 100%. Therefore, for a CPU-bound task in Python, we would have to write multi-process Python program to maximize its performance. ### Thread in Python Because a single-process Python could only use one CPU native thread. No matter how many threads were used in a single-process Python program, a single-process multi-thread Python program could only achieve at most 100% CPU utilization. Therefore, for a CPU-bound task in Python, single-process multi-thread Python program would not improve the performance. However, this does not mean multi-thread is useless in Python. For a I/O-bound task in Python, multi-thread could be used to improve the program performance. ## Multiprocessing VS Threading VS AsyncIO in Python ### Multiprocessing Using Python `multiprocessing`, we are able to run a Python using multiple processes. In principle, a multi-process Python program could fully utilize all the CPU cores and native threads available, by creating multiple Python interpreters on many native threads. Because all the processes are independent to each other, and they don’t share memory. To do collaborative tasks in Python using `multiprocessing`, it requires to use the API provided the operating system. Therefore, there will be slightly large overhead. [![Multi-Process for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUMP.webp)Multi-Process for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUMP.webp) Therefore, for a CPU-bound task in Python, `multiprocessing` would be a perfect library to use to maximize the performance. ### Threading Using Python `threading`, we are able to make better use of the CPU sitting idle when waiting for the I/O. By overlapping the waiting time for requests, we are able to improve the performance. In addition, because all the threads share the same memory, to do collaborative tasks in Python using `threading`, we would have to be careful and use locks when necessary. Lock and unlock make sure that only one thread could write to memory at one time, but this will also introduce some overhead. Note that the threads we discussed here are different to the native threads in CPU core. The number of native threads in CPU core is usually 2 nowadays, but the number of threads in a single-process Python program could be much larger than 2. [![Single-Process Multi-Thread for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Threading.webp)Single-Process Multi-Thread for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Threading.webp) Therefore, for a I/O-bound task in Python, `threading` could be a good library candidate to use to maximize the performance. It should also be noted that all the threads are in a pool and there is an executer from the operating system managing the threads deciding who to run and when to run. This can be a short-coming of `threading` because the operating system actually knows about each thread and can interrupt it at any time to start running a different thread. This is called pre-emptive multitasking since the operating system can pre-empt your thread to make the switch. ### AsyncIO Given `threading` is using multi-thread to maximize the performance of a I/O-bound task in Python, we wonder if using multi-thread is necessary. The answer is no, if you know when to switch the tasks. For example, for each thread in a Python program using `threading`, it will really stay idle between the request is sent and the result is returned. If somehow a thread could know the time I/O request has been sent, it could switch to do another task, without staying idle, and one thread should be sufficient to manage all these tasks. Without the thread management overhead, the execution should be faster for a I/O-bound task. Obviously, `threading` could not do it, but we have `asyncio`. Using Python `asyncio`, we are also able to make better use of the CPU sitting idle when waiting for the I/O. What’s different to `threading` is that, `asyncio` is single-process and single-thread. There is an event loop in `asyncio` which routinely measure the progress of the tasks. If the event loop has measured any progress, it would schedule another task for execution, therefore, minimizing the time spent on waiting I/O. This is also called cooperative multitasking. The tasks must cooperate by announcing when they are ready to be switched out. [![Single-Process Single-Thread Asynchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Asyncio.webp)Single-Process Single-Thread Asynchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Asyncio.webp) The short-coming of `asyncio` is that the even loop would not know what are the progresses if we don’t tell it. This requires some additional effort when we write the programs using `asyncio`. ## Summary | Concurrency Type | Features | Use Criteria | Metaphor | |---|---|---|---| | Multiprocessing | Multiple processes, high CPU utilization. | CPU-bound | We have ten kitchens, ten chefs, ten dishes to cook. | | Threading | Single process, multiple threads, pre-emptive multitasking, OS decides task switching. | Fast I/O-bound | We have one kitchen, ten chefs, ten dishes to cook. The kitchen is crowded when the ten chefs are present together. | | AsyncIO | Single process, single thread, cooperative multitasking, tasks cooperatively decide switching. | Slow I/O-bound | We have one kitchen, one chef, ten dishes to cook. | ## Caveats ### HTOP vs TOP `htop` would sometimes misinterpret multi-thread Python programs as multi-process programs, as it would show multiple `PID`s for the Python program. `top` does not have this problem. On StackOverflow, there is also such a [observation](https://stackoverflow.com/questions/38544265/multithreaded-python-program-starting-multiple-processes). ## References - [Speed Up Your Python Program With Concurrency](https://realpython.com/python-concurrency/) - [Async Python: The Different Forms of Concurrency](http://masnun.rocks/2016/10/06/async-python-the-different-forms-of-concurrency/) Multiprocessing VS Threading VS AsyncIO in Python <https://leimao.github.io/blog/Python-Concurrency-High-Level/> ###### Author Lei Mao ###### Posted on 07-11-2020 ###### Updated on 07-11-2020 ###### Licensed under *** [Python,](https://leimao.github.io/tags/Python/) [Concurrency](https://leimao.github.io/tags/Concurrency/) [Share](https://www.addtoany.com/share#url=https%3A%2F%2Fleimao.github.io%2Fblog%2FPython-Concurrency-High-Level%2F&title=Multiprocessing%20VS%20Threading%20VS%20AsyncIO%20in%20Python%20-%20Lei%20Mao%27s%20Log%20Book) [X](https://leimao.github.io/#x) [LinkedIn](https://leimao.github.io/#linkedin) [Email](https://leimao.github.io/#email) [Facebook](https://leimao.github.io/#facebook) [WeChat](https://leimao.github.io/#wechat) [Line](https://leimao.github.io/#line) [Telegram](https://leimao.github.io/#telegram) [Blogger](https://leimao.github.io/#blogger) ### Like this article? Support the author with [Paypal]() [Buy me a coffee](https://www.buymeacoffee.com/leimao) [Control Python AsyncIO Coroutine Interactively](https://leimao.github.io/blog/Control-Python-AsyncIO-Coroutine-Interactively/) [Parallel Gzip - Pigz](https://leimao.github.io/blog/Parallel-Gzip-Pigz/) ### Comments ![Lei Mao](https://leimao.github.io/images/author_images/Lei-Bio-Medium-High-Res.jpg) Lei Mao Artificial Intelligence Machine Learning Computer Science Menlo Park, California Posts [1330](https://leimao.github.io/archives) Categories [8](https://leimao.github.io/categories) Tags [804](https://leimao.github.io/tags) [Follow](https://github.com/leimao) [Sponsor](https://github.com/sponsors/leimao) ### Advertisement ### Catalogue - [1Introduction]() - [2CPU-Bound VS I/O-Bound]() - [2\.1CPU-Bound]() - [2\.2I/O-Bound]() - [3Process VS Thread in Python]() - [3\.1Process in Python]() - [3\.2Thread in Python]() - [4Multiprocessing VS Threading VS AsyncIO in Python]() - [4\.1Multiprocessing]() - [4\.2Threading]() - [4\.3AsyncIO]() - [5Summary]() - [6Caveats]() - [6\.1HTOP vs TOP]() - [7References]() [![Lei Mao's Log Book](https://leimao.github.io/images/favicon/android-chrome-512x512.png)](https://leimao.github.io/) © 2017-2026 Lei Mao Powered by [Hexo](https://hexo.io/) & [Icarus](https://github.com/ppoffice/hexo-theme-icarus) Site UV: Site PV: [×]() Posts [Tools IntroductionThis is a memo of the tools that I commonly use but often forget where to find. Online C](https://leimao.github.io/miscellaneous/tools/) [MOOC Certificates IntroductionMOOC, massive open online course, is an online course aimed at unlimited participation a](https://leimao.github.io/miscellaneous/mooc/) [Stephen Marsland - Machine Learning Book 2nd Ed IntroductionI purchased and read Stephen Marsland’s machine learning textbook “Machine Learning: An](https://leimao.github.io/reading/Stephen-Marsland-Book-Machine-Learning-2nd/) [John Carreyrou - Bad Blood IntroductionI have two degrees in life science related disciplines, however, I did not know the exis](https://leimao.github.io/reading/John-Carreyrou-Bad-Blood/) [黄易 - 寻秦记 引言现在回想起来,自从小学毕业之后我就没看过任何长篇小说了。金庸和古龙的小说也都是在读小学时因为比较闲才看完的。之后虽然没有再读过长篇小说,但是长篇小说改编的电视剧,游戏或者漫画等却接触过不少,而黄易](https://leimao.github.io/reading/Wong-Yik-A-Step-Into-The-Past/) Pages [Lei Mao Who am IMy name is Lei Mao, and I am a Systems Software Engineer at Meta. My research and engineerin](https://leimao.github.io/) [Curriculum Vitae CareerMeta (October, 2025 - Now)I am getting started as a Systems Software Engineer at Meta at Menlo](https://leimao.github.io/curriculum/) [FAQs Frequently Asked QuestionsHow do I follow and get updates from this website?The best way to follow a](https://leimao.github.io/faq/) [Publications Machine Learning @ NVIDIAConference Articles Advancing Weight and Channel Sparsification with Enhanc](https://leimao.github.io/publication/) [(Untitled) Name City State Rating California Botanic Garden Claremont CA 4.7 Alcatraz City Cruises San Francisc](https://leimao.github.io/downloads/blog/2024-10-30-Discover-Go/museum_addresses) Categories [miscellaneous (miscellaneous)](https://leimao.github.io/miscellaneous/) [reading (reading)](https://leimao.github.io/reading/) [project (project)](https://leimao.github.io/project/) [article (article)](https://leimao.github.io/article/) [blog (blog)](https://leimao.github.io/blog/) Tags [Tool (Tool)](https://leimao.github.io/tags/Tool/) [MOOC (MOOC)](https://leimao.github.io/tags/MOOC/) [Machine Learning (Machine-Learning)](https://leimao.github.io/tags/Machine-Learning/) [Biotechnology (Biotechnology)](https://leimao.github.io/tags/Biotechnology/) [Wuxia (Wuxia)](https://leimao.github.io/tags/Wuxia/) ✓ Thanks for sharing\! [AddToAny](https://www.addtoany.com/ "Share Buttons") [More…](https://leimao.github.io/blog/Python-Concurrency-High-Level/#addtoany "Show all")
Readable Markdown
## Introduction In modern computer programming, concurrency is often required to accelerate solving a problem. In Python programming, we usually have the three library options to achieve concurrency, [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html), [`threading`](https://docs.python.org/3/library/threading.html), and [`asyncio`](https://docs.python.org/3/library/asyncio.html). Recently, I was aware that as a scripting language Python’s behavior of concurrency has subtle differences compared to the conventional compiled languages such as C/C++. [Real Python](https://realpython.com/) has already given a good [tutorial](https://realpython.com/python-concurrency/) with [code examples](https://github.com/realpython/materials/tree/master/concurrency-overview) on Python concurrency. In this blog post, I would like to discuss the `multiprocessing`, `threading`, and `asyncio` in Python from a high-level, with some additional caveats that the Real Python tutorial has not mentioned. I have also borrowed some good diagrams from their tutorial and the readers should give the credits to them on those illustrations. ## CPU-Bound VS I/O-Bound The problems that our modern computers are trying to solve could be generally categorized as CPU-bound or I/O-bound. Whether the problem is CPU-bound or I/O-bound affects our selection from the concurrency libraries `multiprocessing`, `threading`, and `asyncio`. Of course, in some scenarios, the algorithm design for solving the problem might change the problem from CPU-bound to I/O-bound or vice versa. The concept of CPU-bound and I/O-bound are universal for all programming languages. ### CPU-Bound CPU-bound refers to a condition when the time for it to complete the task is determined principally by the speed of the central processor. The faster clock-rate CPU we have, the higher performance of our program will have. [![Single-Process Single-Thread Synchronous for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUBound.webp)Single-Process Single-Thread Synchronous for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUBound.webp) Most of single computer programs are CPU-bound. For example, given a list of numbers, computing the sum of all the numbers in the list. ### I/O-Bound I/O bound refers to a condition when the time it takes to complete a computation is determined principally by the period spent waiting for input/output operations to be completed. This is the opposite of a task being CPU bound. Increasing CPU clock-rate will not increase the performance of our program significantly. On the contrary, if we have faster I/O, such as faster memory I/O, hard drive I/O, network I/O, etc, the performance of our program will boost. [![Single-Process Single-Thread Synchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/IOBound.webp)Single-Process Single-Thread Synchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/IOBound.webp) Most of the web service related programs are I/O-bound. For example, given a list of restaurant names, finding out their ratings on Yelp. ## Process VS Thread in Python ### Process in Python A [global interpreter lock](https://en.wikipedia.org/wiki/Global_interpreter_lock) (GIL) is a mechanism used in computer-language interpreters to synchronize the execution of threads so that only one native thread can execute at a time. An interpreter that uses GIL always allows exactly one native thread to execute at a time, even if run on a multi-core processor. Note that the native thread here is the number of threads in the physical CPU core, instead of the thread concept in the programming languages. Because Python interpreter uses GIL, a single-process Python program could only use one native thread during execution. That means single-process Python program could not utilize CPU more than 100% (we define the full utilization of a native thread to be 100%) regardless whether it is single-process single-thread or single-process multi-thread. Conventional compiled programming languages, such as C/C++, do not have interpreter, not even mention GIL. Therefore, for a single-process multi-thread C/C++ program, it could utilize many CPU cores and many native threads, and the CPU utilization could be greater than 100%. Therefore, for a CPU-bound task in Python, we would have to write multi-process Python program to maximize its performance. ### Thread in Python Because a single-process Python could only use one CPU native thread. No matter how many threads were used in a single-process Python program, a single-process multi-thread Python program could only achieve at most 100% CPU utilization. Therefore, for a CPU-bound task in Python, single-process multi-thread Python program would not improve the performance. However, this does not mean multi-thread is useless in Python. For a I/O-bound task in Python, multi-thread could be used to improve the program performance. ## Multiprocessing VS Threading VS AsyncIO in Python ### Multiprocessing Using Python `multiprocessing`, we are able to run a Python using multiple processes. In principle, a multi-process Python program could fully utilize all the CPU cores and native threads available, by creating multiple Python interpreters on many native threads. Because all the processes are independent to each other, and they don’t share memory. To do collaborative tasks in Python using `multiprocessing`, it requires to use the API provided the operating system. Therefore, there will be slightly large overhead. [![Multi-Process for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUMP.webp)Multi-Process for CPU-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/CPUMP.webp) Therefore, for a CPU-bound task in Python, `multiprocessing` would be a perfect library to use to maximize the performance. ### Threading Using Python `threading`, we are able to make better use of the CPU sitting idle when waiting for the I/O. By overlapping the waiting time for requests, we are able to improve the performance. In addition, because all the threads share the same memory, to do collaborative tasks in Python using `threading`, we would have to be careful and use locks when necessary. Lock and unlock make sure that only one thread could write to memory at one time, but this will also introduce some overhead. Note that the threads we discussed here are different to the native threads in CPU core. The number of native threads in CPU core is usually 2 nowadays, but the number of threads in a single-process Python program could be much larger than 2. [![Single-Process Multi-Thread for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Threading.webp)Single-Process Multi-Thread for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Threading.webp) Therefore, for a I/O-bound task in Python, `threading` could be a good library candidate to use to maximize the performance. It should also be noted that all the threads are in a pool and there is an executer from the operating system managing the threads deciding who to run and when to run. This can be a short-coming of `threading` because the operating system actually knows about each thread and can interrupt it at any time to start running a different thread. This is called pre-emptive multitasking since the operating system can pre-empt your thread to make the switch. ### AsyncIO Given `threading` is using multi-thread to maximize the performance of a I/O-bound task in Python, we wonder if using multi-thread is necessary. The answer is no, if you know when to switch the tasks. For example, for each thread in a Python program using `threading`, it will really stay idle between the request is sent and the result is returned. If somehow a thread could know the time I/O request has been sent, it could switch to do another task, without staying idle, and one thread should be sufficient to manage all these tasks. Without the thread management overhead, the execution should be faster for a I/O-bound task. Obviously, `threading` could not do it, but we have `asyncio`. Using Python `asyncio`, we are also able to make better use of the CPU sitting idle when waiting for the I/O. What’s different to `threading` is that, `asyncio` is single-process and single-thread. There is an event loop in `asyncio` which routinely measure the progress of the tasks. If the event loop has measured any progress, it would schedule another task for execution, therefore, minimizing the time spent on waiting I/O. This is also called cooperative multitasking. The tasks must cooperate by announcing when they are ready to be switched out. [![Single-Process Single-Thread Asynchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Asyncio.webp)Single-Process Single-Thread Asynchronous for I/O-Bound](https://leimao.github.io/images/blog/2020-07-11-Python-Concurrency-High-Level/Asyncio.webp) The short-coming of `asyncio` is that the even loop would not know what are the progresses if we don’t tell it. This requires some additional effort when we write the programs using `asyncio`. ## Summary | Concurrency Type | Features | Use Criteria | Metaphor | |---|---|---|---| | Multiprocessing | Multiple processes, high CPU utilization. | CPU-bound | We have ten kitchens, ten chefs, ten dishes to cook. | | Threading | Single process, multiple threads, pre-emptive multitasking, OS decides task switching. | Fast I/O-bound | We have one kitchen, ten chefs, ten dishes to cook. The kitchen is crowded when the ten chefs are present together. | | AsyncIO | Single process, single thread, cooperative multitasking, tasks cooperatively decide switching. | Slow I/O-bound | We have one kitchen, one chef, ten dishes to cook. | ## Caveats ### HTOP vs TOP `htop` would sometimes misinterpret multi-thread Python programs as multi-process programs, as it would show multiple `PID`s for the Python program. `top` does not have this problem. On StackOverflow, there is also such a [observation](https://stackoverflow.com/questions/38544265/multithreaded-python-program-starting-multiple-processes). ## References - [Speed Up Your Python Program With Concurrency](https://realpython.com/python-concurrency/) - [Async Python: The Different Forms of Concurrency](http://masnun.rocks/2016/10/06/async-python-the-different-forms-of-concurrency/)
ML Classification
ML Categories
/Computers_and_Electronics
99.5%
/Computers_and_Electronics/Programming
97.8%
/Computers_and_Electronics/Programming/Scripting_Languages
83.3%
Raw JSON
{
    "/Computers_and_Electronics": 995,
    "/Computers_and_Electronics/Programming": 978,
    "/Computers_and_Electronics/Programming/Scripting_Languages": 833
}
ML Page Types
/Article
99.9%
/Article/Tutorial_or_Guide
95.7%
Raw JSON
{
    "/Article": 999,
    "/Article/Tutorial_or_Guide": 957
}
ML Intent Types
Informational
99.9%
Raw JSON
{
    "Informational": 999
}
Content Metadata
Languageen
AuthorLei Mao
Publish Time2020-07-11 07:00:00 (5 years ago)
Original Publish Time2020-07-11 07:00:00 (5 years ago)
RepublishedNo
Word Count (Total)1,782
Word Count (Content)1,387
Links
External Links31
Internal Links50
Technical SEO
Meta NofollowNo
Meta NoarchiveNo
JS RenderedYes
Redirect Targetnull
Performance
Download Time (ms)50
TTFB (ms)50
Download Size (bytes)10,176
Shard143 (laksa)
Root Hash2566890010099092343
Unparsed URLio,github!leimao,/blog/Python-Concurrency-High-Level/ s443