{"authors":[{"name":"Mayuresh Waykole","url":"https://mayureshwaykole.com/"}],"description":"Engineering writing by Mayuresh Waykole on distributed systems, observability, reliability, and AI engineering.","favicon":"https://mayureshwaykole.com/favicon-32x32.png","feed_url":"https://mayureshwaykole.com/feed.json","home_page_url":"https://mayureshwaykole.com/","icon":"https://mayureshwaykole.com/apple-touch-icon.png","image":"https://mayureshwaykole.com/images/social-preview.png","items":[{"authors":[{"name":"Mayuresh Waykole"}],"content_html":"\u003cp\u003eRecently we\u0026rsquo;ve seen an abundance of async-only APIs in C# and common libraries like HttpClient.\nIn most cases, this encourages async/await best practices, especially on the server side, but there are exceptions.\nIn some situations, we need to call these async methods synchronously.\u003c/p\u003e\n\u003cp\u003eOne common way to do this is \u003ccode\u003eGetAwaiter().GetResult()\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTask\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003estring\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e pingTask \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e new \u003cspan style=\"color:#a6e22e\"\u003eHttpClient\u003c/span\u003e().\u003cspan style=\"color:#a6e22e\"\u003eGetStringAsync\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://google.com\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003evar webpage \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e pingTask.\u003cspan style=\"color:#a6e22e\"\u003eGetAwaiter\u003c/span\u003e().\u003cspan style=\"color:#a6e22e\"\u003eGetResult\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003eGetAwaiter().GetResult()\u003c/code\u003e call blocks the calling thread and this can cause thread starvation.\u003c/p\u003e\n\u003cp\u003eConsider an example where you want to fetch a few webpages in parallel.\nFor simplicity, we will just call \u003ccode\u003egoogle.com\u003c/code\u003e.\nThe function looks like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c#\" data-lang=\"c#\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/// \u0026lt;summary\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/// Synchronously pings the URL and returns the result.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/// \u0026lt;/summary\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/// \u0026lt;returns\u0026gt;Webpage content\u0026lt;/returns\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estring\u003c/span\u003e PingUrlSync()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// Call the asynchronous method and wait for the result\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Task\u0026lt;\u003cspan style=\"color:#66d9ef\"\u003estring\u003c/span\u003e\u0026gt; pingTask = \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e HttpClient().GetStringAsync(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://google.com\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e webpage = pingTask.GetAwaiter().GetResult();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e webpage;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAt first glance, this looks fine. If we run this once, we\u0026rsquo;re sure to get the webpage string.\nIf we want to run this a few times in parallel, we\u0026rsquo;d do something like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c#\" data-lang=\"c#\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// A randomly high number of iterations\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e taskCount = \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// Start multiple tasks to ping the URL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i = \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; i \u0026lt; taskCount; i++)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    tasks.Add(Task.Run(() =\u0026gt; { PingUrlSync(); }));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis is where the problem starts.\nIf we add some logging and constrain the .NET thread pool so the number of worker threads matches the number of processors, this code will hang.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-log\" data-lang=\"log\"\u003eprocessor count: 8\nMax worker threads set to 17\nMax completion port threads set to 8\nPingUrlSync\t, Iteration: 0, ThreadId: 4\nPingUrlSync\t, Iteration: 1, ThreadId: 3\nPingUrlSync\t, Iteration: 3, ThreadId: 8\nPingUrlSync\t, Iteration: 2, ThreadId: 7\nPingUrlSync\t, Iteration: 4, ThreadId: 9\nPingUrlSync\t, Iteration: 5, ThreadId: 10\nPingUrlSync\t, Iteration: 6, ThreadId: 11\nPingUrlSync\t, Iteration: 7, ThreadId: 12\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eIn this post, we\u0026rsquo;ll understand why this code hangs and how to investigate such issues in Visual Studio.\u003c/p\u003e\n\u003ch2 id=\"task-parallel-library\"\u003eTask Parallel Library\u003c/h2\u003e\n\u003cp\u003eWe need a little background on the Task Parallel Library to understand what\u0026rsquo;s going on.\u003c/p\u003e\n\u003cp\u003eTask Parallel Library (TPL) is a set of public types and APIs in .NET that simplify the process of adding parallelism and concurrency to applications. It was introduced in .NET Framework 4.0 and is the recommended way to write multithreaded and parallel code.\u003c/p\u003e\n\u003cp\u003eTPL handles the partitioning of work, scheduling of threads on the ThreadPool, cancellation support, state management, and other low-level details. It scales the degree of concurrency dynamically to most efficiently use all available processors.\u003c/p\u003e\n\u003cp\u003eWhen running async/await or threaded tasks, all these tasks get pushed to a queue and are scheduled on the thread pool.\u003c/p\u003e\n\u003ch3 id=\"asyncawait\"\u003eAsync/Await\u003c/h3\u003e\n\u003cp\u003eEssentially, async/await code is internally a set of tasks.\u003c/p\u003e\n\u003cp\u003eWhen you call an async method, it returns a task that represents the I/O work.\nThe return value is a task with a return type.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eTask\u0026lt;string\u0026gt; pingTask = new HttpClient().GetStringAsync(\u0026quot;https://google.com\u0026quot;);\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eWhen you call \u003ccode\u003eawait\u003c/code\u003e on this task, the runtime frees the calling thread and schedules the rest of your code as a continuation.\nThat continuation runs only after the awaited task is complete.\u003c/p\u003e\n\u003ch2 id=\"thread-starvation\"\u003eThread Starvation\u003c/h2\u003e\n\u003cp\u003eNow that we have background on the problem and some basics about the Task Parallel Library, we can dig deeper.\u003c/p\u003e\n\u003cp\u003eWhen we create the PingUrlSync task, it gets added to the queue and is waiting to be scheduled.\nWhen calling \u003ccode\u003eGetAwaiter().GetResult()\u003c/code\u003e, we are asking the runtime to wait on the current thread for the task to complete.\nEssentially, for every \u003ccode\u003ePingUrlSync\u003c/code\u003e call, we now have at least 1 new task and 1 blocked thread.\nWhen we call this method multiple times concurrently, we have multiple blocked threads.\u003c/p\u003e\n\u003cp\u003eThe CLR thread pool is not an unlimited resource. At some point, if you run enough concurrent tasks, you\u0026rsquo;ll end up blocking all the threads, and tasks in the queue will not have any threads available to run on.\u003c/p\u003e\n\u003cp\u003eAt this point, the blocked threads are waiting for tasks to complete, and tasks in the queue are waiting for a thread to free up so they can do their work.\nWe now have a deadlock, and it results in a hung state.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-mermaid\" data-lang=\"mermaid\"\u003egraph TD\n    subgraph \u0026#34;Task Queue\u0026#34;\n        T1[Task 1]\n        T2[Task 2]\n        T3[Task 3]\n        T4[Task 4]\n        T5[Task 5]\n    end\n    \n    subgraph \u0026#34;Thread Pool (3 threads)\u0026#34;\n        TP1[Thread 1] --\u0026gt; |\u0026#34;Blocked waiting for Task 1\u0026#34;| B1[Blocked]\n        TP2[Thread 2] --\u0026gt; |\u0026#34;Blocked waiting for Task 2\u0026#34;| B2[Blocked]\n        TP3[Thread 3] --\u0026gt; |\u0026#34;Blocked waiting for Task 3\u0026#34;| B3[Blocked]\n    end\n    \n    T1 --\u0026gt; TP1\n    T2 --\u0026gt; TP2\n    T3 --\u0026gt; TP3\n    \n    style T1 fill:#f9f,stroke:#333,stroke-width:2px\n    style T2 fill:#f9f,stroke:#333,stroke-width:2px\n    style T3 fill:#f9f,stroke:#333,stroke-width:2px\n    style T4 fill:#f9f,stroke:#333,stroke-width:2px\n    style T5 fill:#f9f,stroke:#333,stroke-width:2px\n    style TP1 fill:#bbf,stroke:#333,stroke-width:2px\n    style TP2 fill:#bbf,stroke:#333,stroke-width:2px\n    style TP3 fill:#bbf,stroke:#333,stroke-width:2px\n    style B1 fill:#f66,stroke:#333,stroke-width:2px\n    style B2 fill:#f66,stroke:#333,stroke-width:2px\n    style B3 fill:#f66,stroke:#333,stroke-width:2px\n\u003c/code\u003e\u003c/pre\u003e","date_modified":"2026-04-11T09:06:24Z","date_published":"2025-03-20T22:12:03Z","id":"https://mayureshwaykole.com/posts/get-awaiter/","image":"https://mayureshwaykole.com/images/social-preview.png","summary":"Deep dive into thread pool exhaustion caused by GetAwaiter().GetResult() in C#. Learn why blocking on async code leads to deadlocks and how to fix it.","tags":["C#","Async/Await","Concurrency","Thread Pool","Thread Starvation"],"title":"Thread Exhaustion Due to GetAwaiter().GetResult() in C#","url":"https://mayureshwaykole.com/posts/get-awaiter/"},{"authors":[{"name":"Mayuresh Waykole"}],"content_html":"\u003ch1 id=\"events\"\u003eEvents\u003c/h1\u003e\n\u003cp\u003eIn this post, we will explore what events are, how they are used and the advantages. Throughout the post we will build our way up to a complete event driven program.\nWe will use python do this, since python has no inherent way to handle events we need to build everything from scratch.\u003c/p\u003e\n\u003ch3 id=\"events-1\"\u003eEvents\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eEvents\u003c/code\u003e in the simplest terms are notifications.\nSoftware written such that it largely relies on events for communication is said to be \u003ccode\u003eEvent Driven\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eThe most common operations to do with an event are\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eListen\u003c/li\u003e\n\u003cli\u003eEmit\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eA program that would like to take some action when an event has occured, \u003ccode\u003elistens\u003c/code\u003e for that event.\u003c/p\u003e\n\u003cp\u003eA program \u003ccode\u003eEmits\u003c/code\u003e an Event when it would like to notify that some change has occured.\u003c/p\u003e\n\u003cp\u003eLets start with a bare bones structure with nothing but the method definition\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Events.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eemit\u003c/span\u003e(event):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# doSomething\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003elisten\u003c/span\u003e(event):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# doSomething\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eBelow is the test code. This will be used to run the Events that we write and test it.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# events.test.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Events \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e E\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Does nothing yet.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expectation: to be triggered when the event occurs.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eE\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;FIRST_EVENT\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Does nothing yet.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Expectation: to trigger the listener.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eE\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eemit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;FIRST_EVENT\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNow that we have the general structure of the code, lets define the behaviour.\u003c/p\u003e\n\u003cp\u003eEvents are supposed to facilitate real time communication.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eThe execution flow is defined by the events\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eWhat this means is that any listener listening on \u003ccode\u003eFIRST_EVENT\u003c/code\u003e will be triggered when that event is emitted. To do this, our listeners have to first let us know what they are listening on. Usually, the listener wants to run some code when an event occurs. This code can be put in a function, referred to as a \u003ccode\u003ecallback\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eUpdating our test to reflect the callback\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# events.test.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Events \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e E\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# callback function\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eprintData\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;an event occured\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# when event occurs, call printData\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eE\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elisten(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;FIRST_EVENT\u0026#39;\u003c/span\u003e, printData)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# send event\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eE\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eemit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;FIRST_EVENT\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \u0026gt; an event occured\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# sends event\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eE\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eemit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;SECOND_EVENT\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# \u0026gt; \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe test code when run with the events library should print \u0026ldquo;an event occured\u0026rdquo; when the FIRST_EVENT is sent. However when the SECOND_EVENT is sent, nothing should happen since there is no one listening to the second event.\u003c/p\u003e\n\u003cp\u003eLets look at the \u003ccode\u003eevents.py\u003c/code\u003e implementation to see if we can make it behave as expected in the test.\u003c/p\u003e\n\u003cp\u003eThe first thing we need is to map events to listeners.\n\u003ccode\u003eAn event can have multiple listeners.\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eSo a good data structure to use will be a HashMap/Dictionary in python.\nThe key will be the event and value will be a list of callback functions.\nIt should look something like this\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;EVENT1_NAME\u0026#39;\u003c/span\u003e: [\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003elistener1 callback\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003elistener2 callback\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eHere we do the core implementation of listening to an event.\nThe code comments provide a detailed explanation of whats happening\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# Events.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# dictionary. key = Event, value = list of callbacks\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eEventListenerMap \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eThe callback is added to list for an event\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003elisten\u003c/span\u003e(event, callback):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# if its a new event, initialize a list\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e event \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e EventListenerMap:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        EventListenerMap[event] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# add callback function to list of listeners for that event\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    EventListenerMap[event]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(callback)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eRuns all the callback functions for that event\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eemit\u003c/span\u003e(event):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# get list of callback for event\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    listeners \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e EventListenerMap\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(event)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# If theres atleast one listener\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e listeners \u003cspan style=\"color:#f92672\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# iterate over list and call the function \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e# passed by the listener\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e callback \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e listeners:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            callback()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis gives the basic implementation of our event library.\u003c/p\u003e\n\u003cp\u003eLive code can be seen here \u003ca href=\"https://repl.it/@MayureshWaykole/events-Basics\"\u003ehttps://repl.it/@MayureshWaykole/events-Basics\u003c/a\u003e\u003c/p\u003e\n","date_modified":"2019-05-01T22:12:03Z","date_published":"2019-05-01T22:12:03Z","id":"https://mayureshwaykole.com/posts/events/","image":"https://mayureshwaykole.com/images/social-preview.png","summary":"Learn event-driven programming patterns in Python. A practical guide to implementing custom event systems with code examples.","tags":["Python","Events","Event-Driven Architecture"],"title":"Events","url":"https://mayureshwaykole.com/posts/events/"}],"language":"en","title":"Mayuresh Waykole","version":"https://jsonfeed.org/version/1.1"}