{"id":4188,"date":"2023-08-28T21:15:51","date_gmt":"2023-08-29T04:15:51","guid":{"rendered":"https:\/\/ioflood.com\/blog\/?p=4188"},"modified":"2024-02-05T14:19:12","modified_gmt":"2024-02-05T21:19:12","slug":"python-multiprocessing","status":"publish","type":"post","link":"https:\/\/ioflood.com\/blog\/python-multiprocessing\/","title":{"rendered":"Python Multiprocessing | Threaded Programming Guide"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/ioflood.com\/blog\/wp-content\/uploads\/2023\/08\/Artistic-depiction-of-concurrent-execution-and-multiprocessing-in-Python-featuring-multiple-threads-and-interlocking-gears-300x300.jpg\" alt=\"Artistic depiction of concurrent execution and multiprocessing in Python featuring multiple threads and interlocking gears\" width=\"300\" height=\"300\" title=\"\"><\/figure>\n<\/div>\n<p>Ever wondered how to make your Python programs run faster and more efficiently? Like a skilled conductor leading an orchestra, Python&#8217;s multiprocessing module allows your programs to perform multiple tasks simultaneously.<\/p>\n<p>This power-packed feature leverages the full potential of your computer&#8217;s processors, making your Python programs run like a breeze.<\/p>\n<p>In this comprehensive guide, we will walk you through the ins and outs of Python multiprocessing. We will start from understanding the basic usage and gradually move towards mastering advanced techniques.<\/p>\n<p>So, are you ready to dive into the world of Python multiprocessing? Let&#8217;s get started!<\/p>\n<h2>TL;DR: How Do I Use Multiprocessing in Python?<\/h2>\n<blockquote><p>\n  Python&#8217;s multiprocessing module allows you to create separate processes, which can run concurrently. Here&#8217;s a simple example:\n<\/p><\/blockquote>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process\n\ndef print_func(continent='Asia'):\n    print('The name of continent is : ', continent)\n\nif __name__ == \"__main__\":  # confirms that the code is under main function\n    names = ['America', 'Europe', 'Africa']\n    procs = []\n    proc = Process(target=print_func)  # instantiating without any argument\n    procs.append(proc)\n    proc.start()\n\n    # instantiating process with arguments\n    for name in names:\n        proc = Process(target=print_func, args=(name,))\n        procs.append(proc)\n        proc.start()\n\n    # complete the processes\n    for proc in procs:\n        proc.join()\n\n# Output:\n# The name of continent is :  Asia\n# The name of continent is :  America\n# The name of continent is :  Europe\n# The name of continent is :  Africa\n<\/code><\/pre>\n<p>This simple Python script leverages the multiprocessing module to create four separate processes. Each process is tasked with printing the name of a continent. The <code>Process<\/code> class is used to create processes, and the <code>start()<\/code> method to initiate them. The <code>join()<\/code> method ensures that the main program waits for all processes to complete before proceeding.<\/p>\n<blockquote><p>\n  Intrigued? Read on for a more detailed explanation and advanced usage scenarios of Python&#8217;s multiprocessing module!\n<\/p><\/blockquote>\n<h2>Getting Started with Python Multiprocessing<\/h2>\n<p>Python\u2019s multiprocessing module is a powerful tool that enables you to create and manage multiple processes concurrently. It is particularly useful when you need to perform several tasks simultaneously or when you want to leverage the full power of your multi-core processor.<\/p>\n<p>Here&#8217;s a simple example of how to use the multiprocessing module:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process\n\ndef worker():\n    print('Worker process is working.')\n\nif __name__ == '__main__':\n    processes = [Process(target=worker) for _ in range(5)]\n\n    for process in processes:\n        process.start()\n\n    for process in processes:\n        process.join()\n\n# Output:\n# Worker process is working.\n# Worker process is working.\n# Worker process is working.\n# Worker process is working.\n# Worker process is working.\n<\/code><\/pre>\n<p>In this example, we first import the <code>Process<\/code> class from the multiprocessing module. We then define a simple function <code>worker()<\/code> that prints a message when called. In the <code>if __name__ == '__main__'<\/code> block, we create a list of five <code>Process<\/code> objects, each targeting the <code>worker()<\/code> function. We then start each process using the <code>start()<\/code> method and wait for all processes to complete using the <code>join()<\/code> method.<\/p>\n<p>The multiprocessing module provides a simple and intuitive API for managing concurrent processes. It allows you to create processes that run independently of each other, thus making your program faster and more efficient. However, it&#8217;s important to be mindful of potential pitfalls such as deadlocks and race conditions which can occur in concurrent programming. We&#8217;ll delve into these issues and how to avoid them in later sections.<\/p>\n<h2>Leveraging Python Multiprocessing: Beyond the Basics<\/h2>\n<p>As you become more comfortable with Python&#8217;s multiprocessing module, you&#8217;ll discover it offers much more than just running tasks concurrently. It provides advanced features like worker pools, process synchronization, and state sharing, which can significantly enhance your program&#8217;s performance and efficiency.<\/p>\n<h3>Worker Pools in Python Multiprocessing<\/h3>\n<p>Worker pools are a powerful feature that allows you to manage multiple worker processes. Instead of manually creating, starting, and joining processes, you can use a pool to automatically manage these tasks.<\/p>\n<p>Here&#8217;s an example of how to use a worker pool:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Pool\n\ndef square(n):\n    return n * n\n\nif __name__ == '__main__':\n    with Pool(5) as p:\n        numbers = [1, 2, 3, 4, 5]\n        results = p.map(square, numbers)\n        print(results)\n\n# Output:\n# [1, 4, 9, 16, 25]\n<\/code><\/pre>\n<p>In this example, we create a pool of five worker processes using the <code>Pool<\/code> class. We then use the <code>map<\/code> method to apply a function <code>square<\/code> to a list of numbers. The <code>map<\/code> method distributes the tasks to the worker processes and collects the results.<\/p>\n<h3>Synchronizing Processes in Python Multiprocessing<\/h3>\n<p>In concurrent programming, it&#8217;s often necessary to synchronize processes to ensure they don&#8217;t interfere with each other. Python&#8217;s multiprocessing module provides several ways to synchronize processes, such as Locks, Semaphores, and Conditions.<\/p>\n<p>Here&#8217;s an example of how to use a Lock to synchronize processes:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process, Lock\n\ndef printer(lock, text):\n    lock.acquire()\n    try:\n        print(text)\n    finally:\n        lock.release()\n\nif __name__ == '__main__':\n    lock = Lock()\n    for i in range(10):\n        Process(target=printer, args=(lock, 'Hello world',)).start()\n\n# Output:\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n# Hello world\n<\/code><\/pre>\n<p>In this example, we use a <code>Lock<\/code> to ensure that only one process can access the <code>print<\/code> function at a time. This prevents the processes from interfering with each other and ensures the output is as expected.<\/p>\n<h3>Sharing State Between Processes in Python Multiprocessing<\/h3>\n<p>Python&#8217;s multiprocessing module also allows processes to share state using shared memory or server processes. However, sharing state between processes can be tricky and should be done carefully to avoid issues like race conditions.<\/p>\n<p>Here&#8217;s an example of how to share state using a Value:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process, Value\n\ndef adder(num, val):\n    num.value += val\n\nif __name__ == '__main__':\n    num = Value('d', 0.0)\n    Process(target=adder, args=(num, 1.0)).start()\n    Process(target=adder, args=(num, 2.0)).start()\n    Process(target=adder, args=(num, 3.0)).start()\n    print(num.value)\n\n# Output:\n# 6.0\n<\/code><\/pre>\n<p>In this example, we use a <code>Value<\/code> to share a double (represented by &#8216;d&#8217;) between three processes. Each process adds a different value to the shared <code>Value<\/code>. The final value of <code>num<\/code> is the sum of the values added by each process.<\/p>\n<p>These advanced features of Python&#8217;s multiprocessing module can greatly enhance your program&#8217;s performance and efficiency. However, they should be used carefully and correctly to avoid potential issues.<\/p>\n<h2>Exploring Concurrency Alternatives in Python<\/h2>\n<p>While Python&#8217;s multiprocessing module is a powerful tool for achieving concurrency, it&#8217;s not the only option. Python offers other methods for concurrent execution, such as threading and asyncio. Additionally, third-party libraries like Celery provide alternative ways to handle concurrent tasks.<\/p>\n<h3>Python Threading<\/h3>\n<p>Threading is a technique for concurrent execution where a single process contains multiple threads that can run simultaneously. Here&#8217;s a simple example of how to use threading in Python:<\/p>\n<pre><code class=\"language-python line-numbers\">import threading\n\ndef worker(number):\n    print(f'Worker {number} is working.')\n\nif __name__ == '__main__':\n    for i in range(5):\n        threading.Thread(target=worker, args=(i,)).start()\n\n# Output:\n# Worker 0 is working.\n# Worker 1 is working.\n# Worker 2 is working.\n# Worker 3 is working.\n# Worker 4 is working.\n<\/code><\/pre>\n<p>In this example, we create and start five threads, each targeting the worker function and passing a unique number as an argument. However, due to Python&#8217;s Global Interpreter Lock (GIL), threading might not provide a significant performance boost for CPU-bound tasks.<\/p>\n<h3>Python Asyncio<\/h3>\n<p>Asyncio is a library to write single-threaded concurrent code using coroutines, multiplexing I\/O access over sockets and other resources, running network clients and servers, and other related primitives. Here&#8217;s a simple example:<\/p>\n<pre><code class=\"language-python line-numbers\">import asyncio\n\nasync def main():\n    print('Hello')\n    await asyncio.sleep(1)\n    print('world')\n\nasyncio.run(main())\n\n# Output:\n# Hello\n# (after one second) world\n<\/code><\/pre>\n<p>This example demonstrates the use of asyncio to handle IO-bound tasks efficiently. However, it might not be suitable for CPU-bound tasks due to the single-threaded nature of the event loop.<\/p>\n<h3>Celery<\/h3>\n<p>Celery is a powerful third-party library that allows you to distribute tasks across multiple worker nodes. It supports both task queues for distributing work across threads or machines and scheduling for executing tasks at specific times. However, it requires a message broker like RabbitMQ or Redis, which might increase the complexity of your setup.<\/p>\n<p>In conclusion, while Python&#8217;s multiprocessing module is a powerful tool for achieving concurrency, other methods like threading, asyncio, and third-party libraries like Celery provide alternative ways to handle concurrent tasks. Depending on your specific needs and the nature of your tasks (CPU-bound or IO-bound), you might find one method more suitable than others. It&#8217;s recommended to understand the advantages and disadvantages of each method and choose the one that fits your needs best.<\/p>\n<h2>Navigating Common Pitfalls in Python Multiprocessing<\/h2>\n<p>While Python multiprocessing offers powerful capabilities, it&#8217;s not without its challenges. Issues such as deadlocks, race conditions, and shared state problems can arise. However, with the right knowledge, these can be effectively managed.<\/p>\n<h3>Dealing with Deadlocks<\/h3>\n<p>A deadlock is a situation where a process is unable to proceed because it&#8217;s waiting for resources held by another process, which in turn is waiting for resources held by the first process. Deadlocks can cause your program to hang indefinitely. Here&#8217;s an example of a potential deadlock situation:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process, Lock\n\ndef worker(lock1, lock2):\n    with lock1:\n        with lock2:\n            print('Hello, world!')\n\nif __name__ == '__main__':\n    lock1, lock2 = Lock(), Lock()\n    Process(target=worker, args=(lock1, lock2)).start()\n    Process(target=worker, args=(lock2, lock1)).start()\n<\/code><\/pre>\n<p>In this example, the two worker processes may deadlock if they acquire their locks in different orders. To avoid deadlocks, always ensure that locks are acquired and released in the same order.<\/p>\n<h3>Managing Race Conditions<\/h3>\n<p>A race condition occurs when two or more processes access and manipulate shared data concurrently, and the outcome of the execution depends on the particular order in which the access takes place. Here&#8217;s an example of a race condition:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Process, Value\n\ndef adder(num, val):\n    num.value += val\n\nif __name__ == '__main__':\n    num = Value('d', 0.0)\n    Process(target=adder, args=(num, 1.0)).start()\n    Process(target=adder, args=(num, 2.0)).start()\n    print(num.value)\n\n# Output:\n# 1.0 or 2.0 or 3.0\n<\/code><\/pre>\n<p>In this example, the final value of <code>num<\/code> depends on the order in which the processes execute. To avoid race conditions, use locks or other synchronization mechanisms to ensure that only one process can access the shared data at a time.<\/p>\n<h3>Handling Shared State Issues<\/h3>\n<p>Sharing state between processes can be tricky due to the isolated nature of processes. If not managed properly, it can lead to inconsistencies and unexpected behavior. The multiprocessing module provides several ways to share state, such as Value and Array, but they should be used carefully to avoid potential issues.<\/p>\n<p>In conclusion, while Python multiprocessing is a powerful tool, it&#8217;s not without its challenges. However, with the right knowledge and careful coding, these challenges can be effectively managed.<\/p>\n<h2>Understanding Multiprocessing and Multithreading<\/h2>\n<p>Before we delve deeper into Python multiprocessing, it&#8217;s crucial to understand the fundamental concepts of multiprocessing and multithreading and how they differ.<\/p>\n<h3>Multiprocessing vs. Multithreading<\/h3>\n<p>In a nutshell, multiprocessing involves running tasks on different processors simultaneously. Each process runs independently and has its own Python interpreter and memory space. This independence makes multiprocessing ideal for CPU-bound tasks, as it can effectively leverage multiple CPU cores.<\/p>\n<p>On the other hand, multithreading involves running different threads within the same process. Threads share the same memory space, making communication between them faster and more efficient. However, due to this shared memory space, threads need to be coordinated to prevent conflicts, especially when they&#8217;re modifying shared data.<\/p>\n<p>Here&#8217;s a simple comparison of multiprocessing and multithreading:<\/p>\n<table>\n<thead>\n<tr>\n<th>&#8212;<\/th>\n<th>Multiprocessing<\/th>\n<th>Multithreading<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Suitability<\/td>\n<td>CPU-bound tasks<\/td>\n<td>I\/O-bound tasks<\/td>\n<\/tr>\n<tr>\n<td>Memory Space<\/td>\n<td>Separate for each process<\/td>\n<td>Shared among all threads<\/td>\n<\/tr>\n<tr>\n<td>Communication<\/td>\n<td>Slower due to interprocess communication<\/td>\n<td>Faster due to shared memory<\/td>\n<\/tr>\n<tr>\n<td>Coordination<\/td>\n<td>Less necessary due to process isolation<\/td>\n<td>Necessary to prevent conflicts<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>The Global Interpreter Lock (GIL) in Python<\/h3>\n<p>In Python, the Global Interpreter Lock (GIL) is a mechanism that prevents multiple native threads from executing Python bytecodes simultaneously. This lock is necessary because Python&#8217;s memory management is not thread-safe.<\/p>\n<p>The GIL can be a bottleneck in multithreaded programs, as it prevents threads from running in true parallel on multiple cores. However, each Python process has its own Python interpreter and its own GIL, so the GIL&#8217;s impact is mitigated in multiprocessing.<\/p>\n<p>Here&#8217;s an example to illustrate the GIL&#8217;s impact:<\/p>\n<pre><code class=\"language-python line-numbers\">import time\nimport threading\n\ndef count(n):\n    while n &gt; 0:\n        n -= 1\n\n# Single thread\nstart = time.time()\ncount(100000000)\nend = time.time()\nprint('Single thread:', end - start)\n\n# Two threads\nstart = time.time()\nthread1 = threading.Thread(target=count,args=(50000000,))\nthread2 = threading.Thread(target=count,args=(50000000,))\nthread1.start()\nthread2.start()\nthread1.join()\nthread2.join()\nend = time.time()\nprint('Two threads:', end - start)\n\n# Output:\n# Single thread: X seconds\n# Two threads: Y seconds\n<\/code><\/pre>\n<p>This example demonstrates that the two-thread version doesn&#8217;t run twice as fast as the single-thread version due to the GIL, even though we&#8217;re running on a multi-core processor.<\/p>\n<p>In conclusion, Python&#8217;s multiprocessing module provides a solution to the GIL limitation by allowing us to create separate processes that can run concurrently on different processors. This makes it a powerful tool for optimizing the performance of CPU-bound tasks in Python.<\/p>\n<h2>Python Multiprocessing: A Key for Data-Intensive Applications<\/h2>\n<p>Python&#8217;s multiprocessing module isn&#8217;t just a tool for optimizing performance; it&#8217;s a key that unlocks new possibilities for data-intensive applications. Whether you&#8217;re web scraping, analyzing large data sets, or building complex simulations, multiprocessing can help you get the job done faster and more efficiently.<\/p>\n<h3>Multiprocessing in Data-Intensive Applications<\/h3>\n<p>Consider a data analysis task where you need to apply a complex computation to a large dataset. Without multiprocessing, you&#8217;d have to apply the computation to each data point sequentially, which could take a significant amount of time. With multiprocessing, you could split the dataset into chunks and process them concurrently, potentially reducing the computation time drastically.<\/p>\n<p>Here&#8217;s an example of how you might use multiprocessing in a data analysis task:<\/p>\n<pre><code class=\"language-python line-numbers\">from multiprocessing import Pool\nimport numpy as np\n\ndef compute(data):\n    return np.sum(data ** 2)\n\nif __name__ == '__main__':\n    data = np.random.rand(1000000)\n    with Pool(4) as p:\n        results = p.map(compute, np.array_split(data, 4))\n    total = np.sum(results)\n    print(total)\n\n# Output:\n# [A random number]\n<\/code><\/pre>\n<p>In this example, we use a <code>Pool<\/code> of worker processes to compute the sum of squares of a large array of random numbers. We split the array into four chunks and process them concurrently. The final result is the sum of the results from each chunk.<\/p>\n<h3>Python Multiprocessing in Web Scraping<\/h3>\n<p>In web scraping, you often need to send multiple requests to different URLs. Without multiprocessing, you&#8217;d have to send these requests one by one, waiting for each to complete before sending the next. With multiprocessing, you can send multiple requests concurrently, significantly speeding up the scraping process.<\/p>\n<h3>Exploring Related Concepts<\/h3>\n<p>While multiprocessing is a powerful tool, it&#8217;s just one piece of the concurrency puzzle in Python. Other concepts like asynchronous programming with <code>asyncio<\/code>, distributed computing with <code>dask<\/code> or <code>ray<\/code>, and parallel programming with <code>joblib<\/code> or <code>concurrent.futures<\/code> can further enhance your ability to write efficient, high-performance Python code.<\/p>\n<h2>Further Resources for Python Modules<\/h2>\n<p>If you&#8217;re interested in diving deeper into these topics, we recommend checking out the following resources:<\/p>\n<ul>\n<li><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/python-modules\/\">Python Modules Mastery: Step-by-Step<\/a> &#8211; Discover modules for networking, socket programming, and web requests.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/python-threading\/\">Concurrent Programming with Python Threading<\/a> &#8211; Learn to create multithreaded applications using Python&#8217;s threading.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/ioflood.com\/blog\/python-priority-queue-practical-guide-with-examples\/\">Priority Queue Implementation in Python<\/a> &#8211; Dive deep into priority queue concepts and real-world examples.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/martinxpn.medium.com\/multiprocessing-in-python-72-100-days-of-python-db0e9c66b0b3\" target=\"_blank\" rel=\"noopener\">Multiprocessing in Python<\/a> explains the concept and implementation of multiprocessing in Python in this Medium article.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/www.linuxjournal.com\/content\/multiprocessing-python\" target=\"_blank\" rel=\"noopener\">Multiprocessing in Python Article<\/a> on Linux Journal breaks down the complexities of Python multiprocessing.<\/p>\n<\/li>\n<li>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/pymotw.com\/2\/multiprocessing\/basics.html\" target=\"_blank\" rel=\"noopener\">Python Multiprocessing Basics<\/a> &#8211; Learn about the functions and usage of Python&#8217;s multiprocessing module with the Python Module of the Week series.<\/p>\n<\/li>\n<\/ul>\n<p>Remember, the key to mastering concurrency in Python is understanding the underlying concepts and knowing when and how to apply them in your code.<\/p>\n<h2>Python Multiprocessing: A Recap and Review<\/h2>\n<p>In this comprehensive guide, we&#8217;ve explored Python&#8217;s multiprocessing module, a powerful tool for optimizing the performance of CPU-bound tasks. We&#8217;ve seen how to create, start, and manage processes, and how to share state and synchronize processes to prevent issues like race conditions and deadlocks.<\/p>\n<p>We&#8217;ve also looked at advanced features like worker pools, which can simplify the management of multiple worker processes, and considered the potential pitfalls and how to avoid them.<\/p>\n<p>In addition to Python&#8217;s built-in multiprocessing module, we&#8217;ve also touched upon alternative approaches to handle concurrent tasks, such as threading, asyncio, and third-party libraries like Celery. These alternatives each have their strengths and weaknesses, and the best choice depends on your specific needs and the nature of your tasks.<\/p>\n<p>Here&#8217;s a quick comparison of the methods we&#8217;ve discussed:<\/p>\n<table>\n<thead>\n<tr>\n<th>&#8212;<\/th>\n<th>Multiprocessing<\/th>\n<th>Threading<\/th>\n<th>Asyncio<\/th>\n<th>Celery<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Suitability<\/td>\n<td>CPU-bound tasks<\/td>\n<td>I\/O-bound tasks<\/td>\n<td>I\/O-bound tasks<\/td>\n<td>Distributed tasks<\/td>\n<\/tr>\n<tr>\n<td>Memory Space<\/td>\n<td>Separate for each process<\/td>\n<td>Shared among all threads<\/td>\n<td>Shared among all tasks<\/td>\n<td>Depends on the setup<\/td>\n<\/tr>\n<tr>\n<td>Communication<\/td>\n<td>Interprocess communication<\/td>\n<td>Shared memory<\/td>\n<td>Event loop<\/td>\n<td>Message broker<\/td>\n<\/tr>\n<tr>\n<td>Coordination<\/td>\n<td>Less necessary<\/td>\n<td>Necessary<\/td>\n<td>Necessary<\/td>\n<td>Necessary<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Remember, the key to mastering concurrency in Python is understanding the underlying concepts and knowing when and how to apply them in your code. Python&#8217;s multiprocessing module is a powerful tool, but it&#8217;s just one piece of the puzzle. Don&#8217;t be afraid to explore other options and choose the one that fits your needs best.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ever wondered how to make your Python programs run faster and more efficiently? Like a skilled conductor leading an orchestra, Python&#8217;s multiprocessing module allows your programs to perform multiple tasks simultaneously. This power-packed feature leverages the full potential of your computer&#8217;s processors, making your Python programs run like a breeze. In this comprehensive guide, we [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":12211,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[121,123],"tags":[],"class_list":["post-4188","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming-coding","category-python","cat-121-id","cat-123-id","has_thumb"],"_links":{"self":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/comments?post=4188"}],"version-history":[{"count":10,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4188\/revisions"}],"predecessor-version":[{"id":16989,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/posts\/4188\/revisions\/16989"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/media\/12211"}],"wp:attachment":[{"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/media?parent=4188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/categories?post=4188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ioflood.com\/blog\/wp-json\/wp\/v2\/tags?post=4188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}