Moment For Technology

What does the absence of a SynchronizationContext mean?

Posted on Aug. 5, 2023, 9:17 a.m. by Leslie Harmon
Category: The back-end Tag: The back-end Micro service architecture

This is the 18th day of my participation in the August Genwen Challenge.More challenges in August

  • ? welcome to like: ? collect ⭐ message ? if there are mistakes please correct, give people rose, hand left lingering fragrance!
  • ? This article was originally written by Webmote and originally published by Nuggets.
  • ? author's motto: life is toss about, when you don't toss about life, life will start to toss about you, let us come on together! ? ? ?

Preface ? and the.NET Framework class libraries have been interfering with many of the weirdest things that are said and done about async programming Core. As a result, a large number of newbies core console/ core also have a deep misunderstanding of how to handle asynchrony, so digging into the essential differences would be enormously helpful for myself and many more newbies core.

? 1. No SynchronizationContext

Yes, the SynchronizationContext, which is deeply embedded in traditional ASP.NET, was cut in the ASP.NET Core Core Console projects. *** WinForm is a synchronizationContext for Netcore

? 2. What is a synchronization context

MSDN description: provides the basic function of propagating synchronization context in various synchronization models. Because multithreaded programming is extremely difficult, it requires an understanding of numerous concepts and tools. For this purpose, Microsoft provides the SynchronizationContext class.

Unfortunately, many developers don't even know about this useful tool.

In most projects based on the.NET Framework, the concept of a synchronous context is supported. This includes ASP.NET, Windows Forms, Windows Presentation Foundation (WPF), Silverlight, or others.

Traditional, for example, is designed with one thread per request until the request completes. This leads to low thread utilization because the creation of Web pages often relies on database queries and Web service calls, and the thread processing the request must wait until all these operations are complete. With asynchronous pages, the thread processing the request can start each operation and then return to the ASP.NET thread pool; When the operation ends, another thread in the ASP.NET thread pool can complete the request.

ASP.NET SynchronizationContext is installed when the thread pool thread executes the page code. When entrusted capture AspNetSynchronizationContext column, it restores the original page logo and area, and then executed directly entrusted. Even if the delegate is queued "asynchronously" by calling Post, the delegate is called directly.

Conceptually, AspNetSynchronizationContext context is very complicated. In the lifetime of an asynchronous page, the context starts with a thread from the ASP.NET thread pool. After the asynchronous request starts, the context does not contain any threads. When the asynchronous request ends, the thread pool thread that executes its completion routine enters the context. These could be the threads that started the request, but are more likely to be any threads that are idle when the operation completes.

  • Provides a way to queue units of work into context
  • Each thread has a "current" context
  • Reserve a large number of asynchronous operations
  • The most notable thing about the ASP.NET (system.web) SynchronizationContext is that it executes "exclusively," in other words, one at a time per delegate (but not necessarily sequentially).
  • If the same application of multiple operations at the same time to complete, AspNetSynchronizationContext ensure only perform one at a time. They can be executed on any thread, but that thread will have the identity and region of the original page.

A common example is using WebClient in an asynchronous Web page. DownloadDataAsync captures the current SynchronizationContext and then executes its DownloadDataCompleted event in that context. When the page starts executing, ASP.NET assigns one of its threads to execute the code in the page. The page might call DownloadDataAsync and return; ASP.NET counts outstanding asynchronous operations to see if the page is complete. When the WebClient object downloads the requested data, it receives notification from a thread pool thread. This thread will raise DownloadDataCompleted in the captured context. This context will remain in the same thread, but will ensure that event handlers run with the correct identity and locale.

Having said so much, do you understand?

Oh, oh, let's get some technical points straight. SynchronizationContext allows one thread to communicate with another thread. Suppose you have two threads, Thread1 and Thread2. Thread1 is doing some work, and Thread1 wants to execute code on Thread2. The possibility of an implementation method is to ask Thread2 SynchronizationContext objects, it provides Thread1, then Thread1 can call SynchronizationContext. Send, execute code in Thread2. Sounds like magic... Well, there's something you should know. Not every thread has it attached to the SynchronizationContext. SynchronizationContextUI thread is always a thread.

? 3. Why is the synchronization context removed

Take a step back, is a good question why AspNetSynchronizationContext at ASP.NET Core will be deleted. While I'm not aware of any discussions within the team on this topic, I think it's for two reasons: performance and simplicity. Consider performance first.

When the asynchronous handler resumes execution on older versions of ASP.NET, continuing operations are queued to the request context. Subsequent work must wait for any other work that has been queued (you can only run one at a time). When a lucky line is prepared, the thread is fetched from the thread pool, entered into the request context, and execution of the handler continues. "Reentering" the request context involves many housekeeping tasks, such as setting httpContext.current and the identity and culture of the Current thread.

With the contextless ASP.NET Core method, when the asynchronous handler resumes execution, threads are fetched from the thread pool and execution continues. Context queues are avoided, and there is no need to "enter" the request context. In addition, the async/await mechanism is highly optimized for context-less situations. Asynchronous requests do very little work. So ASP.NET Core doesn't have HttpContext.current. That's one of the reasons.

Simplicity is another aspect of the decision. AspNetSynchronizationContext effect is very good, but it contains some tricky part, especially in the aspect of identity management.

Ok, so there's no SynchronizationContext. What does this mean for developers?

? 4. You can block asynchronous code

The first and most obvious result is that no context await is captured. This means that blocking asynchronous code does not cause a deadlock. You can use task.getawaiter ().getresult () (or task.wait or task.result) without worrying about deadlocks.

However, you should not do this, which is what we call Sync over Async. Because the moment you block asynchronous code, you give up all the benefits of asynchronous code. When the thread is blocked, the increased scalability of the asynchronous handler is cancelled.

There are two cases in (traditional) ASP.NET that unfortunately must be prevented: ASP.NET MVC filters and suboperations. However, in ASP.NET Core, the entire pipeline is completely asynchronous. Both filters and view components execute asynchronously. So here's what you need to pay attention to

  • Tasks continue to be queued in the thread pool and can be run in parallel
  • HttpContext is not thread-safe!
  • If task.wait or task.result is used to block a Task, there is no deadlock

In summary, ideally, you should strive to implement everything using Async. But you can also block without danger if your code needs to. No danger means no deadlock risk, but because it takes two threads to do so, on Windows, performance may be reduced but the application remains responsive; On Linux, you might encounter thread pool exhaustion.

As Daniel explains, a lot of Linux I/O is actually pseudo-asynchronous. That is, the underlying API is synchronous, and the application must burn threads to process them asynchronously, increasing the likelihood of thread pool exhaustion. The main reason for this is the Linux driver stack, where drivers must support both synchronous and asynchronous operations (in contrast, on Windows, any I/O data transfer must be asynchronous; All synchronization apis are located in the Win32 layer driver above the device). Asynchronous drivers are the hardest thing in the world to write, so Linux lags behind Windows in this area.

? 5. Summary

Well, stay tuned for the next part of this article.

Routine summary, rational view!

Knot is what ah, knot is I want you to praise but can not get lonely. ? ? ?

? have seen this, but also care about a thumbs-up?

? has been liked, but also care about a collection?

? are collected, but also care about a comment?

About (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.