2016-04-07 44 views
1

我是新来的多线程,我很难理解所有的方式来完成任务。我试图在一个大的程序中实现它,但是没有人想要毫无理由地查看所有数千行处理代码,因此我编写了一个简单的测试程序,它使用Sleep()而不是做真正的工作,并使其变得非常简单。Task.Factory.StartNew()或Task.Run()的正确用法?

问题是作为底部。

using System; 
using System.Collections.Concurrent; 
using System.Threading.Tasks; 
using System.Threading; 
namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      BlockingCollection<int> col = new BlockingCollection<int>(); 
      for(int z = 0; z<=50; z++) 
      { 
       col.Add(z); 
      } 

      Console.WriteLine("Hi from main! ThreadID: {0}", Thread.CurrentThread.ManagedThreadId); 
      var parent = Task.Factory.StartNew(() => 
      { 
       Console.WriteLine("Hi from PARENT! ThreadID: {0}", Thread.CurrentThread.ManagedThreadId); 
       foreach (int num in col.GetConsumingEnumerable()) 
       { 
         Thread.Sleep(100); 
         Task.Factory.StartNew(() => 
         { 
          Thread.Sleep(num*100); 
          if (num == 50) 
          { 
           col.CompleteAdding(); //kick out of the foreach loop 
           Thread.Sleep(25000); 
          } 
          Console.WriteLine("Hi from a Child! ThreadID: {0}", Thread.CurrentThread.ManagedThreadId); 

         }, TaskCreationOptions.AttachedToParent); 
       } 
       Console.WriteLine("Parent done making children. ThreadID: {0}", Thread.CurrentThread.ManagedThreadId); 
      }, TaskCreationOptions.LongRunning); 

      var final = parent.ContinueWith((antecedent) => 
      { 
       Console.WriteLine("DONE!"); 
      },TaskContinuationOptions.OnlyOnRanToCompletion 
       ); 

      Console.WriteLine("Calling Wait on final. ThreadID: {0}", Thread.CurrentThread.ManagedThreadId); 
      final.Wait(); 
      Console.ReadLine(); 
     } 
    } 
} 

该代码将51个元素添加到阻塞集合,然后启动一个名为Parent的任务。 Parent将消耗阻塞集合中的项目,直到它被标记为CompleteAdding()为止。

父任务长时间运行,因为我不希望它从线程池中拉出线程。然后,它应该产生将休眠一段时间的附加的子任务,如果元素是'50',则它调用CompleteAdding()

然后有一个名为final的延续,只有在父项运行完成时才会运行。如果阻塞收集也已完成并且所有子任务也完成,则父节点只能完成。

我然后调用从主final.Wait()(在我的实际程序的final.Wait()将有可能会在OnFormClosing()方法。)

做这一切的整点是为了能够确保该程序关闭所有当前之前运行工作结束,所有排队工作也完成。

这是问题所在。我在很多地方看到我应该使用Task.Run()而不是Task.Factory.StartNew(),所以我尝试将它们更改出来,然后我开始收到错误,说Error CS1643 Not all code paths return a value in lambda expression of type 'Func<Task>'为什么我需要返回值,如果我不想要返回。也是这个Task.Factory.StartNew()的正确使用还是我做一些危险/危险的事情?

note不知道它是否很重要,但在程序中,我打算在睡眠中使用这个设置,像匹配数据并将它发送到oracle数据库。此外,我们不能高于.NET 4.6

+0

您不需要'BlockingCollection'来启动50个任务,只需使用正常的for循环。哦,并**捕获循环变量**。在任务运行时,“num”对于你所有的任务来说可能是50。 –

+0

在我看来,你试图绕过TAP系统设计要做的事情,而是试图使用“长时间运行的线程”自己重新创建它,因为你不想从线程中拉出一个线程池。为什么?这正是TAP系统所做的,它会安排一大堆任务完成,然后确保它们全部完成。 – CodingGorilla

+0

我意识到这一点。目标不是开始50个任务,而是为了确保将所有“工作”(在本例中为int)从队列中拉出,直到我们确信不会再添加任何内容,并且所有工作都在程序完成之前完成退出。但是最终所有应用都是一个工作项目对象,其中包含说明和数据,说明应该采取行动,并且在新数据可用时创建工作项目。可以在一个小时内完成50个项目,或者在20分钟内完成50000个项目。没有办法知道。 – user5999614

回答

0

微软的文档描述Task.Run是异步运行任务的'更简单的方法'。它和Task.Factory.StartNew都返回一个Task和语法是相同的。我有兴趣看到给你编译错误的代码。但是,如果你的代码与Task.Factory.StartNew一起工作,我没有看到改变它的令人信服的理由。

 Task.Run(() => 
     { 
      Console.Write("Doing"); 
      Console.Write("Something"); 
     }); 

     Task.Factory.StartNew(() => 
     { 
      Console.Write("Doing"); 
      Console.Write("Something"); 
     }); 
+0

你可以复制粘贴我的代码,只需将'Task.Factory.StartNew'更改为'Task.Run',并且会重现错误。 – user5999614

0

让我们简化Task.Run版本的代码:

Task.Run(() => { }, TaskCreationOptions.LongRunning); 

这段代码是错误的:there is no overload of Task.Run() accepting TaskCreationOptions。但是C#编译器报告的错误消息(“并非所有代码路径都返回'Func<Task>'类型的lambda表达式中的值”)也是错误的。我认为这是C#编译器中的一个错误,所以I reported it

相关问题