c# 执行上下文

前言

前面介绍了同步上下文,把执行上下文也介绍下。

一句话总结同步上下文,同步上下文就是将一些需要执行的代码能够在我们控制的线程中执行。

什么是执行上线文呢?那必须先给出例子。

正文

var culture = new CultureInfo("fr-FR");
CultureInfo.CurrentCulture = culture; // 设置当前线程文化

ThreadPool.QueueUserWorkItem(_ => {
    // 默认会继承调用线程的执行上下文(包括文化设置)
    Console.WriteLine(CultureInfo.CurrentCulture.Name); // 输出 "fr-FR"
});

执行运行输出了fr-FR。

我们知道这两个运行在不同的线程,但是访问CultureInfo.CurrentCulture.Name 都是fr-FR。

那么有人就会问了,是不是CultureInfo.CurrentCulture 是全局的啊?

然并非如此,是当执行ThreadPool.QueueUserWorkItem的时候带过去的。

可通过 ExecutionContext.SuppressFlow() 禁用上下文流动:

ExecutionContext.SuppressFlow(); // 禁止上下文流动
ThreadPool.QueueUserWorkItem(_ => {
    Console.WriteLine(CultureInfo.CurrentCulture.Name); // 输出默认文化(如 "en-US")
});
ExecutionContext.RestoreFlow(); // 恢复流动

这样就不会传输了。

原理是这样的:

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 设置当前线程的文化
        CultureInfo.CurrentCulture = new CultureInfo("fr-FR");

        // 捕获当前执行上下文
        ExecutionContext context = ExecutionContext.Capture();

        // 在线程池中运行任务,并显式还原上下文
        ThreadPool.QueueUserWorkItem(_ =>
        {
            ExecutionContext.Run(context, _ =>
            {
                Console.WriteLine($"当前文化: {CultureInfo.CurrentCulture.Name}"); // 输出 "fr-FR"
            }, null);
        });

        Console.ReadLine();
    }
}

其实是ThreadPool里面给执行上下文做了快照,然后呢当执行的时候就放在这个执行上下文中执行了。

会设置当前的线程的文化:

static async Task Main()
{
	CultureInfo.CurrentCulture = new CultureInfo("fr-FR");
	
	// 在线程池中运行任务,并显式还原上下文
	ThreadPool.QueueUserWorkItem(_ =>
	{
		Console.WriteLine(Thread.CurrentThread.CurrentCulture.Name);
	});
	
	Console.ReadKey();
}

那么我们该如何自定义执行上下文呢?使用localasync:

using System;
using System.Threading;
using System.Threading.Tasks;

public static class ContextParameters
{
    // 定义上下文参数
    public static AsyncLocal<string> RequestId = new AsyncLocal<string>();
    public static AsyncLocal<int> UserId = new AsyncLocal<int>();
}

class Program
{
    static async Task Main()
    {
        // 设置参数
        ContextParameters.RequestId.Value = "Req-123";
        ContextParameters.UserId.Value = 42;

        // 在异步任务中获取参数
        await Task.Run(() =>
        {
            Console.WriteLine($"RequestId: {ContextParameters.RequestId.Value}"); // 输出 "Req-123"
            Console.WriteLine($"UserId: {ContextParameters.UserId.Value}");      // 输出 "42"
        });
    }
}

其他的比较复杂,可以自行去了解这块。

介绍同步上下文,就把执行上下文也提一下,避免混淆。

posted @ 2025-04-23 12:33  敖毛毛  阅读(66)  评论(0)    收藏  举报