C# 如何获取System.Threading.Tasks.Task已完成的通知
我目前正在使用.net 4中新的System.Threading.Tasks功能,用一个新的实现替换一些自制的任务功能 不过我有一个小问题,虽然我能想出一些解决方案,但我希望得到一些建议,一般来说,哪种方法是最好的,如果我在某个地方遗漏了一个技巧 我需要的是一个任意进程能够启动一项任务,但随后继续,而不是等待任务完成。这不是问题,但是当我需要根据任务的结果做一些事情时,我不太确定最好的方法是什么 我看到的所有示例都对任务使用Wait(),直到任务完成,或者引用任务的Result参数。这两个都将阻止启动任务的线程,我不希望这样 我想到了一些解决方案:C# 如何获取System.Threading.Tasks.Task已完成的通知,c#,.net,.net-4.0,C#,.net,.net 4.0,我目前正在使用.net 4中新的System.Threading.Tasks功能,用一个新的实现替换一些自制的任务功能 不过我有一个小问题,虽然我能想出一些解决方案,但我希望得到一些建议,一般来说,哪种方法是最好的,如果我在某个地方遗漏了一个技巧 我需要的是一个任意进程能够启动一项任务,但随后继续,而不是等待任务完成。这不是问题,但是当我需要根据任务的结果做一些事情时,我不太确定最好的方法是什么 我看到的所有示例都对任务使用Wait(),直到任务完成,或者引用任务的Result参数。这两个都将阻
Task
实现,因此您可以使用(阻塞、轮询或等待其WaitHandle
)。在现代C#中,不再需要显式调用ContinueWith()。除了最初被接受的答案,另一种方法是简单地创建一个async
方法,该方法等待任务
,并在任务
完成时执行它想要的任何操作
例如,假设您希望在任务完成时引发名为TaskCompleted
的事件。您可以编写如下方法:
async Task RaiseEventWhenTaskCompleted(Task task)
{
await task;
TaskCompleted?.Invoke(this, EventArgs.Empty);
}
要“注册”等待,只需调用上述方法。根据需要添加异常处理,无论是在上述方法中,还是在最终将观察上述方法返回的任务的某些代码中。您可以将ContinueWith函数与例程一起用作第一个参数,将任务计划程序用作TaskScheduler提供的第二个参数。FromCurrentSynchronizationContext()
事情是这样的:
var task1 = new Task(() => {do_something_in_a_remote_thread();} );
task1.ContinueWith(() => {do_something_in_the_ui_thread();},
TaskScheduler.FromCurrentSynchronizationContext());
我创建了一个小例子来说明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
}
}
使用系统;
使用系统线程;
使用System.Threading.Tasks;
公共课程
{
静态void Main(字符串[]参数)
{
对于(int-cnt=0;cntConsole.WriteLine($“等待{t.Result}毫秒”);
task.Start();//触发并忘记
}
PlayMelodyHiletasarerunning();
}
静态int-NumTasks=>Environment.ProcessorCount;
静态int DoSomething()
{
整数毫秒=随机。下一个(4000)+1000;
WriteLine($“等待{毫秒}毫秒…”);
睡眠(毫秒);
返回毫秒;//作为t.Result使调用方可用
}
静态随机=新随机();
静态无效PlayMelodyHiletasarerunning()
{
Console.Beep(587200);/D
Console.Beep(622200);/D#
Console.Beep(659200);/E
Console.Beep(1047400);//C
Console.Beep(659200);/E
Console.Beep(1047400);//C
Console.Beep(659200);/E
Console.Beep(10471200);//C
Console.Beep(1047200);//C
控制台.Beep(1175200);/D
控制台.Beep(1245200);/D#
控制台.Beep(1319200);/E
Console.Beep(1047200);//C
控制台.Beep(1175200);/D
控制台.Beep(1319400);/E
控制台.Beep(988200);//H
控制台.Beep(1175400);/D
Console.Beep(10471600);//C
}
}
是的,我理解这一点,但它不能解决在启动任务的线程上不调用Task.Wait()(并因此阻塞)就知道任务序列何时完成的问题。我想到的一种方法(如上所述)是使用Task.ContinueWith链接一个引发相关方可以订阅的事件的任务。这将使原始任务保持原子状态。@b威廉:为什么不公开该任务,感兴趣的各方可以调用任务。是否继续使用?我不知道它在什么方面不能解决知道任务何时完成的问题。。。这是一个非阻塞调用,表示“完成后给我回电话”。(或者不公开任务本身,您可以提供自己的方法,然后只在内部调用ContinueWith
。事实上也是如此。)抱歉,您完全正确。我最初阅读了MSDN上的所有内容,包括您发布的所有链接,但出于某种原因,我阅读了Task.ContinueWith,将其他任务作为初始任务完成后执行的参数,而不是简单的操作或函数。非常感谢,阿尔托
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
}
}