我见过很多其他类似的问题,但在那里找不到我的答案。
我的问题是我使用以下流程创建线程:
private void btn_Click(object sender, EventArgs e)
{
service.GetCount(
(count, ex) =>
{
if (ex != null)
return;
for (int i = 0; i < count; i++)
{
service.Get(onItemReceived, i);
}
}
);
}
public void GetCount(Action<int, Exception> callback)
{
var callingThread = TaskScheduler.FromCurrentSynchronizationContext();
Func<int> action = () =>
{
return client.GetCount(); // Synchronous method, could take a long time
};
Action<Task<int>> completeAction = (task) =>
{
Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;
if (callback != null)
callback(task.Result, ex);
};
Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}
public void Get(Action<object, Exception> callback, int index)
{
var callingThread = TaskScheduler.FromCurrentSynchronizationContext();
Func<object> action = () =>
{
return client.Get(index); // Synchronous method, could take a long time
};
Action<Task<object>> completeAction = (task) =>
{
Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;
if (callback != null)
callback(task.Result, ex);
};
Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread);
}
通过这种方式,我的每个服务的异步方法都会回调它们最初被调用的线程(通常是UI线程)。所以我模拟await / async关键字是如何工作的(我不能使用.NET 4.5)。
这种模式的问题在于,在第一次调用“ContinueWith”之后,我莫名其妙地被锁定到了UI线程。因此,在这种情况下,如果我尝试为每个进程生成5个线程同步函数获取,它们将逐个执行而不是并行执行,并且它们将在执行此操作时阻止UI线程,即使我尝试指定TaskCreationOptions.LongRunning。
第一次调用Task.Factory.StartNew时,这种情况从未发生过,只会在第一次回调中的后续调用时发生。
答案 0 :(得分:26)
为了强制启动新线程,您应该在对Task.Factory.StartNew的调用中指定TaskScheduler.Default,如下所示:
Task.Factory.StartNew(action,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith(completeAction);
在我的测试中,您不需要指定TaskCreationOptions.LongRunning来强制后台线程,尽管它不应该受到伤害。