Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何获取System.Threading.Tasks.Task已完成的通知_C#_.net_.net 4.0 - Fatal编程技术网

C# 如何获取System.Threading.Tasks.Task已完成的通知

C# 如何获取System.Threading.Tasks.Task已完成的通知,c#,.net,.net-4.0,C#,.net,.net 4.0,我目前正在使用.net 4中新的System.Threading.Tasks功能,用一个新的实现替换一些自制的任务功能 不过我有一个小问题,虽然我能想出一些解决方案,但我希望得到一些建议,一般来说,哪种方法是最好的,如果我在某个地方遗漏了一个技巧 我需要的是一个任意进程能够启动一项任务,但随后继续,而不是等待任务完成。这不是问题,但是当我需要根据任务的结果做一些事情时,我不太确定最好的方法是什么 我看到的所有示例都对任务使用Wait(),直到任务完成,或者引用任务的Result参数。这两个都将阻

我目前正在使用.net 4中新的System.Threading.Tasks功能,用一个新的实现替换一些自制的任务功能

不过我有一个小问题,虽然我能想出一些解决方案,但我希望得到一些建议,一般来说,哪种方法是最好的,如果我在某个地方遗漏了一个技巧

我需要的是一个任意进程能够启动一项任务,但随后继续,而不是等待任务完成。这不是问题,但是当我需要根据任务的结果做一些事情时,我不太确定最好的方法是什么

我看到的所有示例都对任务使用Wait(),直到任务完成,或者引用任务的Result参数。这两个都将阻止启动任务的线程,我不希望这样

我想到了一些解决方案:

  • 创建一个新线程并启动该线程上的任务,然后使用Wait()或.Result阻止新线程并以某种方式将结果同步回调用方,可能还需要轮询tasks IsCompleted参数

  • 有一个“Notify Completed”(通知已完成)任务,我可以在我要运行的任务完成后启动该任务,然后引发一个静态事件或其他事件

  • 将委托传递到任务的输入中,并调用该委托以通知任务已完成

  • 我可以考虑它们的优缺点,但我特别不喜欢这样的想法,即当使用task类的首要目的之一是从直接使用线程中抽象出来时,必须显式地创建一个新线程来启动任务

    关于最好的方法有什么想法吗?我错过了一些简单的东西吗?“已完成”的活动是否要求太多:)?(当然有一个很好的理由来解释为什么没有!)

    我怀疑你在寻找(或)。这些基本上是说,“当您完成此任务时,执行此操作。”但是,您可以指定多种选项来对其进行更多控制

    MSDN在和中详细介绍了这一点。

    您可以应用

    或者,
    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
        }
    }