- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我的应用程序使用以下代码安排了一个长时间运行的任务:
Task.Factory.StartNew<bool>((a) => WorkTask1(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask1(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkCompletedTask1 已安排并按预期在 UI 上显示结果。根据 WorkTask1 的结果,WorkCompletedTask1 可以使用以下语句安排其他任务:
Task.Factory.StartNew<bool>((a) => WorkTask2(),
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => WorkCompletedTask2(antecedent.Result),
TaskScheduler.FromCurrentSynchronizationContext());
WorkTask2 没有像预期的那样在单独的线程上运行;它在 UI 线程上运行,该线程被阻塞,直到 WorkTask2 完成。我认为 TaskCreationOptions.LongRunning 会保证一个单独的线程。
关于为什么这不起作用的任何建议?我可以从 UI 和非 UI 任务安排添加任务,而不是从 UI 中的 .continuewith 任务。
损坏的示例项目代码
在窗体上带有 button1
按钮的空 Windows 窗体项目中,此代码无法按预期工作(Windows 7 VS2010 Express Net 4.0)。 T2 和 T3 在 UI 线程中运行,而不是工作线程。将 listBox1 添加到 button1 表单并尝试以下操作:
private delegate void DelegateSendMsg(String msg);
private DelegateSendMsg m_DelegateSendMsg;
private TaskScheduler uiSched;
private Process thisProcess;
private string
thisProcessName,
thisProcessId,
uiThreadName,
nonuiStatus = "Non-UI",
uiStatus = "UI";
private void Form1_Load(object sender, EventArgs e)
{
thisProcess = Process.GetCurrentProcess();
thisProcessName = thisProcess.ProcessName;
thisProcessId = thisProcess.Id.ToString();
uiThreadName = CurrentThread;
m_DelegateSendMsg = this.SendMsg;
uiSched = TaskScheduler.FromCurrentSynchronizationContext();
SendMsg("UI thread name is " + CurrentThread);
}
//create the name of the current task
public string CurrentThread
{
get
{
string threadId = null;
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
threadId = thisProcess.Id.ToString() + "=" + thisProcessName;
else
threadId = thisProcessId
+ "=" + thisProcessName
+ "/" + Thread.CurrentThread.Name;
threadId += ":" + Thread.CurrentThread.ManagedThreadId + " ";
return threadId;
}
}
//validate if the function is running in the expected UI state or not
public bool MeetsUIExpectations(string functionName, string expectedStatus)
{
bool rc = true;
string currentThreadName = CurrentThread;
string text =
"Function " + functionName + " running in thread " + currentThreadName;
if ((currentThreadName == uiThreadName) & expectedStatus == uiStatus)
text += ": UI status as expected";
else if ((currentThreadName != uiThreadName) & expectedStatus == nonuiStatus)
text += ": non-UI status as expected";
else
{
text += ": UI status is NOT as expected!"
+ " Expected: " + expectedStatus
+ "; running in thread" + currentThreadName;
rc = false;
}
SendMsg(text);
return rc;
}
//display a single text message
private void SendMsg(String msg)
{
if (this.InvokeRequired)
try { this.Invoke(m_DelegateSendMsg, "UI context switch: " + msg); }
catch (Exception) { }
else
{
listBox1.Items.Add(msg);
listBox1.TopIndex = listBox1.Items.Count - 1;
}
}
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<bool>((a) =>
T1(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T1Completed(antecedent.Result), uiSched);
}
private bool T1()
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T1Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
if (successful)
{
Task.Factory.StartNew<bool>((a) =>
T2(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T2Completed(antecedent.Result), uiSched);
}
}
private bool T2()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T2Completed(bool successful)
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
Task.Factory.StartNew<bool>((a) =>
T3(), TaskScheduler.Default,
TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent)
.ContinueWith(antecedent => T3Completed(antecedent.Result), uiSched);
}
private bool T3()
{
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), nonuiStatus);
int i = 0;
while (i < Int32.MaxValue) i++;
return true;
}
private void T3Completed(bool successful)
{
//get the name of the currently running function and validate UI status
var currentMethod = System.Reflection.MethodInfo.GetCurrentMethod();
MeetsUIExpectations(currentMethod.ToString(), uiStatus);
SendMsg("All functions completed");
}
最佳答案
在 .NET 4.0 中你必须通过 TaskScheduler.Default
明确地。您为此选择了错误的重载(见下文)。
一些通用的东西
在 UI 线程的延续中 TaskScheduler
仍然是FromCurrentSynchronizationContext
返回的UI 线程方法。因此,所有新的 Tasks
除非你传递一个TaskScheduler
,否则你的开始也被安排在UI线程上明确地:
这是一个代码示例:
Task.Factory.StartNew(foo => {}, TaskScheduler.Default)
随意使用任何TaskScheduler
你需要,但你需要明确说明。
获得正确的重载
StartNew<T>
有很多重载.在下面的代码中,您选择了错误的代码,这会导致 TaskScheduler.Default
充当state
(作为 a
传递给 T3
的值)而不是实际调度程序:
var options = TaskCreationOptions.LongRunning
| TaskCreationOptions.AttachedToParent;
// overload with Func<bool>, CancellationToken, options and TaskScheduler
Task.Factory.StartNew<bool>(() => T2(), new CancellationToken(),
options, TaskScheduler.Default);
// overload with Func<object, bool> with state and options
// scheduler acts as state here instead of actual scheduler, and
// is therefore just passed as (a) to T3 (state is an object, thus
// can also be a TaskScheduler instance)
Task.Factory.StartNew<bool>((a) => T3(),
TaskScheduler.Default, // state, not scheduler
options);
显然,通过这种方式您不会获得所需的日程安排,而是上述默认行为。
.NET 4.5 的附加信息
在 .NET 4.5 中,有 TaskContinuationOptions.HideScheduler
改变这种行为。参见 New TaskCreationOptions and TaskContinuationOptions in .NET 4.5 by Stephen Toub有关新选项的更多详细信息,让我引用其中的代码示例:
// code sample copied from blog post stated above
Task.Factory.StartNew(() =>
{
// #2 long-running work, so offloaded to non-UI thread
}).ContinueWith(t =>
{
// #3 back on the UI thread
Task.Factory.StartNew(() =>
{
// #4 compute-intensive work we want offloaded to non-UI thread (bug!)
});
}, CancellationToken.None,
TaskContinuationOptions.HideScheduler, // <-- new option stated in text
TaskScheduler.FromCurrentSynchronizationContext());
工作示例项目代码
在带有 button1
的空 Windows 窗体项目中按钮,此代码按预期工作(Windows 7、.NET 4.0):
private void button1_Click(object sender, EventArgs e)
{
var uiSched = TaskScheduler.FromCurrentSynchronizationContext();
button1.Enabled = false;
// this HardWork-task is not blocking, as we have
// TaskScheduler.Default as the default scheduler
Task.Factory.StartNew(HardWork)
.ContinueWith(t =>
{
button1.Enabled = true;
// this HardWork-task will block, as we are on the
// UI thread scheduler
Task.Factory.StartNew(HardWork)
.ContinueWith(t2 =>
{
button1.Enabled = false;
// this one will not, as we pass TaskScheduler.Default
// explicitly
Task.Factory.StartNew(HardWork,
new CancellationToken(),
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith(t3 =>
{
button1.Enabled = true;
}, uiSched); // come back to UI thread to alter button1
}, uiSched); // come back to UI thread to alter button1
}, uiSched); // come back on UI thread to alter button1
}
public void HardWork()
{
int i = 0;
while(i < Int32.MaxValue) i++;
}
关于c# - 从 UI .continuewith 任务安排任务的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13934274/
此处讨论的代码是用 C# 编写并使用 .netcore 3.1 执行 我有以下代码,它在后台启动工作负载而不等待它完成(即发即忘): public void StartBackgroundWork(I
我正在尝试记录对 API 的请求和响应。我目前正在使用一个 delegatingHandler 来捕获 httpwebresponses 和 httpwebrequests。 处理程序: pr
我遇到了以下我试图理解的异步代码(针对此示例进行了简化): class Program { static async Task Main(string[] args) {
我刚刚开始熟悉 Task Parallel Library,但有一个相当琐碎的问题,我无法找到明确的答案。 以下片段之间有什么区别,我应该在什么时候选择一个而不是另一个? Task t = Task.
我在一个很难重现的竞争条件下运行,从我的代码分析来看,它似乎来自一个不执行(或直到结束才执行)的延续。 这里是一些呈现上下文的伪代码: Task GetObject(string id) {
我看到了 Stephen Cleary 关于 Startnew being dangerous 的博客以及如何continuewith is also dangerous .我想在这里使用它来避免在出
我试图在这个例子中链接执行任务: static List clsTaskList = new List(); private static void Tasks2() { Task t1 =
我有以下代码(https://github.com/avinash0161/OrleansExperiments/tree/c0155b4b0c8c1bfe60aea8624f2cc83a52853d
我们的团队遇到了一个问题,即 ContinueWith() 在主机进程关闭之前不会运行。例如,下面的代码已经在生产环境中运行良好一年了。但是自从我们开始使用更新版本的框架后,我们就遇到了这个问题。 运
我在一堆 LINQ 查询上有一些 GUI。查询需要一些时间来执行,所以我希望 GUI 能够响应并显示繁忙指示器和进度条。许多查询是为了检查数据中存在的某些条件。如果查询返回空结果,应用程序应继续下一个
使用 Visual Studio 2015,针对 FW 4(在 FW 4 下测试不可观察的异常): 我期待这段代码: static void Main(string[] args) { try
如果这是一个简单的问题,请原谅我;我无法用足够通用的方式来表达它来搜索答案。 考虑这段代码: var task = Task.Factory.StartNew(() => Whatever());
使用什么值 ContinueWith(Action continuationAction)对于 CancellationToken , TaskContinuationOptions和 TaskSch
我有这个示例代码: static void Main(string[] args) { var t1 = Task.Run(async () => {
我有一些代码用作轻量级、非阻塞的关键部分。我希望无论 Task.Run 子句中的 _func 和 cancellationToken 发生什么情况,都能保证继续运行,这样finally block 中
我用这个代码 public static void Main() { Task t = new Task(() => { return 43; });
请看下面的代码- static void Main(string[] args) { // Get the task. var task = Task.Factory.StartNew
我有控制台应用程序和代码如下, 我的问题是在ContinueWith任务完成之前,控制台应用程序结束,它不等待continueWith完成,请指教。 请让我知道我遗漏了什么或不正确。 var task
我有以下代码,其中延续代码没有被执行。 using System; using System.Threading; using System.Threading.Tasks; namespace Ko
据我了解,ContinueWith 方法会等待相关任务完成。对于以下代码,这意味着它在完成子任务后就完成了。如果这是真的,为什么它有时会输出0 0 0 和其他时间 0 1 2? static
我是一名优秀的程序员,十分优秀!