我目前正在使用.net 4中的新System.Threading.Tasks功能替换一些新的实现功能。
我有一个轻微的问题,虽然我可以想到一些解决方案,我想要一些建议,通常是最好的方法,如果我在某个地方错过了一个技巧。
我需要的是一个任意进程能够启动一个任务然后继续而不是等待任务完成。不是问题,但是当我需要对任务的结果做一些事情时,我不太确定这样做的最佳方式。
我见过的所有示例都在任务上使用Wait()直到完成或引用任务上的Result参数。这两个都会阻塞启动Task的线程,这是我不想要的。
我想到的一些解决方案:
创建一个新线程并在其上启动任务,然后使用Wait()或.Result来阻止新线程,并以某种方式将结果同步回调用者,可能需要轮询任务IsCompleted参数。< / p>
有一个'Notify Completed'任务,我可以在完成我想要运行的任务后启动,然后引发静态事件或其他事情。
将委托传递给任务的输入并调用该任务以通知任务已完成。
我可以为所有人思考或利弊,但我特别不喜欢必须明确创建一个新线程以启动任务的想法,当使用Task类的目标之一时第一个地方是从直接线程使用中抽象出来。
关于最佳方式的任何想法?我错过了一些简单的事吗? “完成”事件会不会要求太多了:)? (当然有一个很好的理由没有一个!)
答案 0 :(得分:36)
我怀疑您正在寻找Task.ContinueWith
(或Task<T>.ContinueWith
)。这些基本上说,“当你完成这个任务,执行这个动作。”但是,您可以指定各种选项以对其进行更多控制。
MSDN在"How to: Chain Multiple Tasks With Continuations"和"Continuation Tasks"中详细介绍了这一点。
答案 1 :(得分:7)
在现代C#中,不再需要明确调用ContinueWith()
。原始接受答案的替代方法是简单地创建一个async
方法await
Task
有问题的Task
,并在TaskCompleted
完成时执行任何操作。< / p>
例如,假设您想在Task
完成时引发一个名为async Task RaiseEventWhenTaskCompleted(Task task)
{
await task;
TaskCompleted?.Invoke(this, EventArgs.Empty);
}
的事件。您可以编写如下方法:
Task
要“注册”等待,只需调用上述方法即可。根据需要在上面的方法中添加异常处理,或者在最终会观察到上述方法返回的if ($a == 1) $b=2 AND $c=3;
的一些代码中添加异常处理。
答案 2 :(得分:5)
您可以申请task continuation。
或者,Task
实施IAsyncResult,因此您可以使用standard approaches for that interface(阻止,轮询或等待其WaitHandle
)。
答案 3 :(得分:0)
您可以将ContinueWith函数与例程一起用作第一个参数,而将任务计划程序作为TaskScheduler.FromCurrentSynchronizationContext()给定的第二个参数。
它是这样的:
var task1 = new Task(() => {do_something_in_a_remote_thread();} );
task1.ContinueWith(() => {do_something_in_the_ui_thread();},
TaskScheduler.FromCurrentSynchronizationContext());
答案 4 :(得分:0)
Task task = Task.Run ( () => { Thread.Sleep ( 2000 ); } );
task.GetAwaiter ().OnCompleted ( () =>
{
MessageBox.Show ( "the task completed in the main thread", "");
} );
答案 5 :(得分:0)
我创建了一个小例子来说明Jon Skeet的答案,我想与您分享:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
static void Main(string[] args)
{
for (int cnt = 0; cnt < NumTasks; cnt++)
{
var task = new Task<int>(DoSomething); // any other type than int is possible
task.ContinueWith(t => Console.WriteLine($"Waited for {t.Result} milliseconds."));
task.Start(); // fire and forget
}
PlayMelodyWhileTasksAreRunning();
}
static int NumTasks => Environment.ProcessorCount;
static int DoSomething()
{
int milliSeconds = random.Next(4000) + 1000;
Console.WriteLine($"Waiting for {milliSeconds} milliseconds...");
Thread.Sleep(milliSeconds);
return milliSeconds; // make available to caller as t.Result
}
static Random random = new Random();
static void PlayMelodyWhileTasksAreRunning()
{
Console.Beep(587, 200); // D
Console.Beep(622, 200); // D#
Console.Beep(659, 200); // E
Console.Beep(1047, 400); // C
Console.Beep(659, 200); // E
Console.Beep(1047, 400); // C
Console.Beep(659, 200); // E
Console.Beep(1047, 1200); // C
Console.Beep(1047, 200); // C
Console.Beep(1175, 200); // D
Console.Beep(1245, 200); // D#
Console.Beep(1319, 200); // E
Console.Beep(1047, 200); // C
Console.Beep(1175, 200); // D
Console.Beep(1319, 400); // E
Console.Beep(988, 200); // H
Console.Beep(1175, 400); // D
Console.Beep(1047, 1600); // C
}
}