.Net 核心 & SynchronizationContext & Thread.SetData
.Net core & SynchronizationContext & Thread.SetData
据我所知,AspNetCore doesn't have SynchronizationContext
.
That “re-entering” the request context involves a number of
housekeeping tasks, such as setting HttpContext.Current and the
current thread’s identity and culture.
所以我创建了一个简单的 .Net Core Api 项目,其中包含以下操作:
[HttpGet]
[Route("checkVar")]
public async Task<IActionResult> checkVar()
{
Thread.SetData(Thread.GetNamedDataSlot("Random"),4);
await Task.Delay(1000);
var res = Thread.GetData(Thread.GetNamedDataSlot("Random"));
}
令我惊讶的是,res
的值为 4
。我很惊讶,因为我相信 SetData
是同步上下文的一部分。 (不应该存在于 asp.net 核心中)
此外,当我使用 ConfigureAwait(false)
时,我在 res
.
中得到了 null
所以现在我很困惑。因为ConfigureAwait
问题:
如果 asp.net 核心没有 SynchronizationContext,那么为什么 4
在 await
之后可用?为什么 ConfigureAwait
在非 SynchronizationContext 环境中改变结果?
您正在 Thread
上调用 SetData
。你怎么会认为它是 SynchronizationContext
.
的一部分
您可以通过检查 SynchronizationContext.Current
的值轻松测试是否存在当前 SynchronizationContext
- 如果它是 null
,则没有 SynchronizationContext
。
您为测试该代码发出了多少个并发请求?
SynchronizationContext
或不是 framework/runtime 流动上下文的方式(就像在 AsyncLocal<T>
这样的类型中)是通过 ExecutionContext
数据,而不是 Thread
数据。
I was surprised because I believe that SetData was part of the synchronization context. (which should not exist in asp.net core)
没有; SetData
是线程本地存储 (TLS)。所以它被绑定到一个特定的线程。这与同步上下文没有任何关系。
More, when I used ConfigureAwait(false) , I got null in res.
根据您 运行 此代码的时间、服务器的繁忙程度等,您可能会得到 null
或 4
有或没有 ConfigureAwait(false)
。
If asp.net core doesn't have a SynchronizationContext, then why did 4 was available after await ?
这是一个特定于线程的值。 ASP.NET Core 上没有 SynchronizationContext
,您的代码将在任何可用的线程池线程上恢复。如果该线程 碰巧 是启动该方法的同一个线程,那么 TLS 将仍然存在,因为它是针对该特定线程的。
相同的行为实际上适用于 ASP.NET pre-Core。在那种情况下,有一个 SynchronizationContext
,但该上下文未绑定到任何特定线程。就像 ASP.NET Core 一样,ASP.NET pre-Core 上的异步方法可以在任何可用的线程池线程上恢复,因此 TLS 数据在 await
.[=22= 之后可能存在也可能不存在。 ]
为了用数据支持这一理论,请尝试在 await
之前和之后记录 Environment.CurrentManagedThreadId
并查看存在的数据与保持不变的 ID 之间是否存在任何相关性。
据我所知,AspNetCore doesn't have SynchronizationContext
.
That “re-entering” the request context involves a number of housekeeping tasks, such as setting HttpContext.Current and the current thread’s identity and culture.
所以我创建了一个简单的 .Net Core Api 项目,其中包含以下操作:
[HttpGet]
[Route("checkVar")]
public async Task<IActionResult> checkVar()
{
Thread.SetData(Thread.GetNamedDataSlot("Random"),4);
await Task.Delay(1000);
var res = Thread.GetData(Thread.GetNamedDataSlot("Random"));
}
令我惊讶的是,res
的值为 4
。我很惊讶,因为我相信 SetData
是同步上下文的一部分。 (不应该存在于 asp.net 核心中)
此外,当我使用 ConfigureAwait(false)
时,我在 res
.
null
所以现在我很困惑。因为ConfigureAwait
问题:
如果 asp.net 核心没有 SynchronizationContext,那么为什么 4
在 await
之后可用?为什么 ConfigureAwait
在非 SynchronizationContext 环境中改变结果?
您正在 Thread
上调用 SetData
。你怎么会认为它是 SynchronizationContext
.
您可以通过检查 SynchronizationContext.Current
的值轻松测试是否存在当前 SynchronizationContext
- 如果它是 null
,则没有 SynchronizationContext
。
您为测试该代码发出了多少个并发请求?
SynchronizationContext
或不是 framework/runtime 流动上下文的方式(就像在 AsyncLocal<T>
这样的类型中)是通过 ExecutionContext
数据,而不是 Thread
数据。
I was surprised because I believe that SetData was part of the synchronization context. (which should not exist in asp.net core)
没有; SetData
是线程本地存储 (TLS)。所以它被绑定到一个特定的线程。这与同步上下文没有任何关系。
More, when I used ConfigureAwait(false) , I got null in res.
根据您 运行 此代码的时间、服务器的繁忙程度等,您可能会得到 null
或 4
有或没有 ConfigureAwait(false)
。
If asp.net core doesn't have a SynchronizationContext, then why did 4 was available after await ?
这是一个特定于线程的值。 ASP.NET Core 上没有 SynchronizationContext
,您的代码将在任何可用的线程池线程上恢复。如果该线程 碰巧 是启动该方法的同一个线程,那么 TLS 将仍然存在,因为它是针对该特定线程的。
相同的行为实际上适用于 ASP.NET pre-Core。在那种情况下,有一个 SynchronizationContext
,但该上下文未绑定到任何特定线程。就像 ASP.NET Core 一样,ASP.NET pre-Core 上的异步方法可以在任何可用的线程池线程上恢复,因此 TLS 数据在 await
.[=22= 之后可能存在也可能不存在。 ]
为了用数据支持这一理论,请尝试在 await
之前和之后记录 Environment.CurrentManagedThreadId
并查看存在的数据与保持不变的 ID 之间是否存在任何相关性。