【问题标题】:Passing a method parameter using Task.Factory.StartNew使用 Task.Factory.StartNew 传递方法参数
【发布时间】:2011-11-14 20:00:34
【问题描述】:

我有以下代码:

var task = Task.Factory.StartNew(CheckFiles, cancelCheckFile.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

private void CheckFiles()
{
  //Do stuff
}

我现在想修改 CheckFiles 以接受整数和 BlockingCollection 参考

private void CheckFiles(int InputID, BlockingCollection<string> BlockingDataCollection)
{
  //Do stuff
}

我似乎无法像上面那样找到启动此任务的方法。

你能帮忙吗?

谢谢

【问题讨论】:

    标签: c# .net .net-4.0 task-parallel-library


    【解决方案1】:

    最好的选择可能是使用封闭您要显示的变量的 lambda 表达式。

    但是,在这种情况下要小心,尤其是在循环调用它时。 (我提到这一点是因为您的变量是“ID”,这在这种情况下很常见。)如果您在错误的范围内关闭变量,您可能会遇到错误。详情请见Eric Lippert's post on the subject。这通常需要临时制作:

    foreach(int id in myIdsToCheck)
    {
        int tempId = id; // Make a temporary here!
        Task.Factory.StartNew( () => CheckFiles(tempId, theBlockingCollection),
             cancelCheckFile.Token, 
             TaskCreationOptions.LongRunning, 
             TaskScheduler.Default);
    }
    

    另外,如果您的代码与上面的代码类似,您应该小心使用LongRunning 提示 - 对于默认调度程序,这会导致每个任务获得自己的专用线程,而不是使用 ThreadPool。如果您正在创建许多任务,这可能会产生负面影响,因为您将无法获得 ThreadPool 的优势。它通常适用于单个长期运行的任务(因此得名),而不是用于处理集合中的项目等的东西。

    【讨论】:

    • 谢谢。我将循环启动它们。但是我确实需要它作为 LongRunning。我的原始程序使用一个文件,但现在它需要对许多文件执行一些代码。因此我需要传入 ID、BlockingCollection、CancellationTokenSoure 和 StreamReader。但是我没有在问题中添加那些额外的方法参数
    • @Jon:请务必检查这些对象的范围...我刚刚提到了 LongRunning 提示,供您考虑 - 我会说使用 LongRunning 很少是个好主意,特别是在 .NET 4 中,如果您要启动许多任务(即:循环工作),因为线程池通常会提供更好的行为。
    • 循环只是启动任务。最多 4-6 个
    • 我赞同 Reed 关于 LongRunning 的评论。如果你看到传递这个论点而不是成本的好处,我会感到惊讶。
    • @Jon 不,我会使用任务,但除非你真的需要这样做,否则不要标记它们长时间运行。默认情况下,Task 使用 ThreadPool 线程。如果您使用默认的 TaskScheduler 将它们标记为“LongRunning”,您将获得专门为该任务创建的专用线程。这通常是没有必要的,如果处理许多任务,则会绕过线程池的所有优点,这可能会影响子任务的行为等......
    【解决方案2】:
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => MyMethod("param value"));
        }
    
        private static void MyMethod(string p)
        {
            Console.WriteLine(p);
        }
    }
    

    【讨论】:

      【解决方案3】:

      对于传递一个整数,我同意 Reed Copsey 的回答。如果将来您要传递更复杂的构造,我个人喜欢将所有变量作为匿名类型传递。它看起来像这样:

      foreach(int id in myIdsToCheck)
      {
          Task.Factory.StartNew( (Object obj) => 
              {
                 var data = (dynamic)obj;
                 CheckFiles(data.id, theBlockingCollection,
                     cancelCheckFile.Token, 
                     TaskCreationOptions.LongRunning, 
                     TaskScheduler.Default);
              }, new { id = id }); // Parameter value
      }
      

      您可以在我的blog了解更多信息

      【讨论】:

        【解决方案4】:

        将第一个参数构造为Action的实例,例如

        var inputID = 123;
        var col = new BlockingDataCollection();
        var task = Task.Factory.StartNew(
            () => CheckFiles(inputID, col),
            cancelCheckFile.Token,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default);
        

        【讨论】:

          【解决方案5】:

          试试这个,

                  var arg = new { i = 123, j = 456 };
                  var task = new TaskFactory().StartNew(new Func<dynamic, int>((argument) =>
                  {
                      dynamic x = argument.i * argument.j;
                      return x;
                  }), arg, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
                  task.Wait();
                  var result = task.Result;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多