- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题
我有一个带有简单 Web 服务的 ASP.NET 4.0 WebForms 页面 WebMethod
.此方法用作异步/TPL 代码的同步包装器。我面临的问题是内部 Task
有时有一个空 SynchronizationContext
(我的偏好),但有时同步上下文为 System.Web.LegacyAspNetSynchronizationContext
.在我提供的示例中,这并不会真正导致问题,但在我的实际开发场景中可能会导致死锁。
对服务的第一次调用似乎总是使用空同步上下文运行,接下来的几个也可能如此。但是一些快速请求,它开始弹出到 ASP.NET 同步上下文中。
编码
[WebMethod]
public static string MyWebMethod(string name)
{
var rnd = new Random();
int eventId = rnd.Next();
TaskHolder holder = new TaskHolder(eventId);
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Web method thread Id: {1}",
eventId,
Thread.CurrentThread.ManagedThreadId);
var taskResult = Task.Factory.StartNew(
function: () => holder.SampleTask().Result,
creationOptions: TaskCreationOptions.None,
cancellationToken: System.Threading.CancellationToken.None,
scheduler: TaskScheduler.Default)
.Result;
return "Hello " + name + ", result is " + taskResult;
}
TaskHolder
的定义存在:
public class TaskHolder
{
private int _eventId;
private ProgressMessageHandler _prg;
private HttpClient _client;
public TaskHolder(int eventId)
{
_eventId = eventId;
_prg = new ProgressMessageHandler();
_client = HttpClientFactory.Create(_prg);
}
public Task<string> SampleTask()
{
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Pre-task thread Id: {1}",
_eventId,
Thread.CurrentThread.ManagedThreadId);
return _client.GetAsync("http://www.google.com")
.ContinueWith((t) =>
{
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Continuation-task thread Id: {1}",
_eventId,
Thread.CurrentThread.ManagedThreadId);
t.Wait();
return string.Format("Length is: {0}", t.Result.Content.Headers.ContentLength.HasValue ? t.Result.Content.Headers.ContentLength.Value.ToString() : "unknown");
}, scheduler: TaskScheduler.Default);
}
}
TaskScheduler.Default
的理解是
ThreadPool
调度器。换句话说,线程不会在 ASP.NET 线程上结束。根据
this article , “Task Parallel Library 和 PLINQ 的默认调度程序使用 .NET Framework ThreadPool 来排队和执行工作”。基于此,我预计
SynchronizationContext
里面
SampleTask
始终为空。
SampleTask
将在 ASP.NET
SynchronizationContext
上,调用
.Result
在
MyWebMethod
可能陷入僵局。
Task.Run(() => holder.SampleTask()).Result
Task.Factory.StartNew(
() => holder.SampleTask().Result,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
TaskCreationOptions.DenyChildAttach
, 而我
想这是我的问题。但是我在 .NET 4.5 中运行了相同的示例并切换到
TaskCreationOptions.DenyChildAttach
它的行为相同(有时会抓取 ASP.NET 同步上下文)。
Task.Run(() => holder.SampleTask()).Result
Task.Run
实现,但这将涉及开发时间,我宁愿花在更紧迫的问题上(如果可能的话)。
加号 ,我仍然想弄清楚不同的
TaskScheduler
是怎么回事和
TaskCreationOptions
情景。
TaskCreationOptions.PreferFairness
在 .NET 4.0 中似乎表现得如我所愿(所有执行都有一个空同步上下文),但不知道为什么会这样,我很犹豫要不要使用它(它可能不适用于所有场景)。
Task.Factory.StartNew
在同步上下文中安全地“包装”异步方法。或
Task.Run
方法。但这似乎并非如此?
最佳答案
首先,在 ASP.NET 中使用 sync-over-async 通常没有多大意义。您正在承担创建和调度 Task
的开销s,但您不会以任何方式从中受益。
现在,对于你的问题:
My understanding of
TaskScheduler.Default
is that it's theThreadPool
scheduler. In other words, the thread won't end up on the ASP.NET thread.
ThreadPool
也。但这在这里并不重要。相关的是,如果您
Wait()
(或调用
Result
,相同)在
Task
上计划运行(但尚未开始),
TaskScheduler
我决定只运行你的
Task
同步。这被称为“任务内联”。
Task
最终在
SynchronizationContext
上运行,但实际上并没有通过它安排。这意味着实际上没有死锁的风险。
Thanks to being in .NET 4.0, I don't have access to
TaskCreationOptions.DenyChildAttach
, and I thought this was my issue.
DenyChildAttach
无关, 没有
Task
s 那将是
AttachedToParent
.
I've coincidentally found that
TaskCreationOptions.PreferFairness
in .NET 4.0 appears to behave as I'd wish (all executions have a null sync context), but without knowing why this works, I'm very hesitant to use it (it may not work in all scenarios).
PreferFairness
安排
Task
到全局队列(而不是每个
ThreadPool
线程具有的线程本地队列),似乎
Task
来自全局队列的 s 不会被内联。但我不会依赖这种行为,特别是因为它将来会改变。
Curiously, if I don't use ProgressMessageHandler, I don't seem able to replicate the deadlock.
GetAsync()
在没有设置同步上下文的线程上运行。我认为最好的方法是调用
SynchronizationContext.SetSynchronizationContext(null)
在调用
GetAsync()
之前并在之后恢复它。
关于asp.net - 对异步同步的 TaskScheduler 和 SynchronizationContext 感到困惑,无法控制同步上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14973379/
我仍在学习整个任务概念和 TPL。根据我目前的理解,await 使用 SynchronizationContext 函数(如果存在)将任务分派(dispatch)到“某处”。另一方面,Task 类中的
感谢 Jeremy Miller 在 Functional Programming For Everyday .NET Development 中的出色工作,我有一个工作命令执行器,它可以做我想做的一
我使用 SynchronizationContext从 UI 线程上的后台线程调用方法。我读了this post它要求 Send 的差异和 Post .我明白答案并会调用Send每当我需要调用方法的结
我遇到了挂起等待的问题(描述 here )。在研究过程中,我发现调用 SetResult在我的 TaskCompletionSource实际上在调用 SetResult 的线程的上下文中调用等待继续(
public static void Init() { //var task = GetSource1(); //var task = GetSource2(); //var
在异步函数内部使用与外部不同的 SynchronizationContext 时,我的行为令人困惑。 我的大部分程序代码都使用自定义 SynchronizationContext,它只是将 SendO
我正在尝试了解 SynchronizationContext 和 friend 。如果我在例如开始时设置自定义同步上下文控制台应用程序。在什么情况下当前同步上下文将与我的异步操作一起流动?Task 和
我想了解更多关于 SynchronizationContext 的信息,所以我制作了这个简单的控制台应用程序: private static void Main() { var sc = ne
我不知道如何获取给定 Thread 的 SynchronizationContext: Thread uiThread = UIConfiguration.UIThread; Synchronizat
如何比较 SynchronizationContext?似乎同一个 Dispatcher 在使用 BeginInvoke 时可以创建不同的 SynchronizationContext。当我深入研究两
在Programming C#一书中,它有一些关于SynchronizationContext的示例代码。 : SynchronizationContext originalContext = Syn
对于 WinForms 和 WPF,我使用 SynchronizationContext 作为同步到 GUI 线程的方法。最近我遇到了旧式异步回调的问题: private void Button
我有以下代码: [TestMethod] public void StartWorkInFirstThread() { if (SynchronizationContext.Current =
SynchronizationContext 有一个名为 IsWaitNotificationRequired 的属性.出于其目的,docs有话要说: Determines if wait notif
说,我有以下代码: IPrincipal capturedPrincipal = Thread.CurrentPrincipal; myseq.AsParallel().Select(x => {
这是一个非常基本的问题,我想是的,但是我找不到任何明确的答案。 SynchronizationContext.Post()线程安全吗? 我有一个成员变量,它保存主线程的上下文,并且从多个线程中调用_c
SynchronizationContext.Current 在主线程上为 null,我很难弄清楚这一点。 static class Program { /// //
我正在创建 SynchronizationContext 的 STA 版本以用于 Windows Workflow 4.0。我想知道在发布回调时如何处理异常。 SynchronizationConte
简而言之,我已经实现了一个派生自 SynchronizationContext 的类,以便 GUI 应用程序可以轻松地使用在 GUI 线程以外的线程上引发的事件。我非常感谢对我的实现的评论。具体来说,
我有两个线程,一个是主线程,另一个是我创建的线程来做一些工作。我不明白当我从另一个线程调用 originalContext.Post(主线程的 SyncronizationContext)时会发生什么
我是一名优秀的程序员,十分优秀!