【问题标题】:ThreadPool in C#C#中的线程池
【发布时间】:2012-01-25 02:45:10
【问题描述】:

我有两个问题:

  1. 有没有办法插入一个无法获得的ThreadPool functoin 对象作为参数(要向线程池插入一个函数,它需要是返回 void 和一个参数 - 对象的函数)例如我想插入这个函数:double foo(int a,double b,string c)?
  2. 有没有办法让wait 在池中线程(如加入)?

【问题讨论】:

    标签: c# threadpool


    【解决方案1】:

    这两个问题的答案是否定的,不是使用原生 ThreadPool,虽然如果你将输入的 args 打包到状态对象中并编写机制以提供等待功能并获得工作结果,则可以达到相同的结果项目方法。

    http://smartthreadpool.codeplex.com/ 做你想做的一切;

        public static void Main(string[] args)
        {
            var threadPool = new SmartThreadPool();
    
            IWorkItemResult<int> workItem=null;
    
            SmartThreadPool.WaitAll(new IWaitableResult[ ]{workItem = threadPool.QueueWorkItem(new Amib.Threading.Func<int, int, int>(Add), 1, 2)});
    
            Console.WriteLine(workItem.Result);
    
            Console.ReadLine();
        }
    
        public static int Add(int a, int b)
        {
            return a+b;
        }
    

    【讨论】:

    【解决方案2】:

    关于您的第一个问题,创建一个调用foo 的正确签名的新方法(返回void,一个对象参数)。如果您需要将特定参数传递给 foo,则创建一个类或结构或使用Tuple&lt;int, double, double&gt; 并将其转换为对象以将其传递给ThreadMethod,然后返回Tuple 以获取foo 的参数。

    void ThreadMethod(object obj)
    {
        var args = (Tuple<int, double, double>)obj;
    
        foo(args.Item1, args.Item2, args.Item3);
    }
    

    回复。第二个问题,你必须自己创建线程,这样你才能保留一个Thread 对象来加入。

    【讨论】:

    • 1.这才是重点!我的功能必须在这个签名中,我不能改变它。 2.我想把它插入到池中。
    • 创建一个新函数,调用无法更改的函数。
    【解决方案3】:

    第一个问题

    我认为你可以创建一个新类作为参数

    示例

    interface IAction
    {
        void Do();
    }
    
    
        class SubClass : IAction
        {
            object _param;
            public SubClass(object o)
            {
                _param = o;
            }
    
            public void Do()
            {
               // your current code in here
            }
        }
    
    
            SubClass sc = new SubClass("paramter");
    
            System.Threading.ThreadPool.QueueUserWorkItem(action => {
    
                var dosomething = action as IAction;
                dosomething.Do();
    
            }, sc);
    

    因此,您无需更改当前函数中的任何代码...

    【讨论】:

      【解决方案4】:

      对于第一部分,最简单的方法可能是:

      根据您的描述假设一种方法:

      public double foo(int a, double b, string c)
      {
          ...
      }
      

      你可以在线程池中排队:

      ThreadPool.QueueUserWorkItem(o => foo(a, b, c));
      

      对于第二部分,虽然您不能在 ThreadPool 线程上等待,但您可以在线程池上异步调用方法,并等待它们完成(这似乎是您要寻找的)。

      再次假设Foo 方法定义如上。

      为 Foo 定义一个委托:

      private delegate double FooDelegate(int a, double b, string c);
      

      然后使用 FooDelegate 的 BeginInvoke/EndInvoke 方法异步调用 Foo:

      // Create a delegate to Foo
      FooDelegate fooDelegate = Foo;
      
      // Start executing Foo asynchronously with arguments a, b and c.
      var asyncResult = fooDelegate.BeginInvoke(a, b, c, null, null);
      
      // You can then wait on the completion of Foo using the AsyncWaitHandle property of asyncResult
      if (!asyncResult.CompletedSynchronously)
      {
          // Wait until Foo completes
          asyncResult.AsyncWaitHandle.WaitOne();
      }
      
      // Finally, the return value can be retrieved using:
      var result = fooDelegate.EndInvoke(asyncResult);
      

      解决 cmets 中提出的问题。如果您想并行执行多个函数调用并等待它们全部返回后再继续,您可以使用:

      // Create a delegate to Foo
      FooDelegate fooDelegate = Foo;
      
      var asyncResults = new List<IAsyncResult>();
      
      // Start multiple calls to Foo() in parallel. The loop can be adjusted as required (while, for, foreach).
      while (...)
      {
          // Start executing Foo asynchronously with arguments a, b and c.
          // Collect the async results in a list for later
          asyncResults.Add(fooDelegate.BeginInvoke(a, b, c, null, null));
      }
      
      // List to collect the result of each invocation
      var results = new List<double>();
      
      // Wait for completion of all of the asynchronous invocations
      foreach (var asyncResult in asyncResults)
      {
          if (!asyncResult.CompletedSynchronously)
          {
              asyncResult.AsyncWaitHandle.WaitOne();
          }
      
          // Collect the result of the invocation (results will appear in the list in the same order that the invocation was begun above.
          results.Add(fooDelegate.EndInvoke(asyncResult));
      }
      
      // At this point, all of the asynchronous invocations have returned, and the result of each invocation is stored in the results list.
      

      【讨论】:

      • 你能在你的例子周围抛出一个循环吗,这是我需要的,但是当你坐在那里等待结果时,看不到如何循环它(有多个函数调用)第一次打电话。
      • @ganders 我已对答案进行了编辑以解决您的问题。如果您需要更多详细信息,我建议您发布一个单独的问题。
      • 感谢铱星的快速反应。 while 循环中的 results 变量是否应该是 asyncResults 变量?
      • @ganders 是的,对不起,在写答案的中途将其重命名。编辑修复。
      【解决方案5】:

      执行此操作的经典方式如下所示,但正如 Iridium 所展示的,现在有更紧凑的方式执行此操作。如果您使用的是 .NET 4,则可以使用并行 API 或更准确地说是 Tasks 以使其更容易。

      public class MyWorker
      {
          private int _a;
          private double _b;
          private string _c;
          Action complete
      
          public MyWorker(int a,double b,string c)
          {
              _a = a;
              _b = b;
              _c = c;
          }
      
          public void Run(object state)
          {
              double result = Foo();
          }
      
          private double Foo()
          {
              // Do something with _a, _b, _c
          }
      }
      
      MyWorker worker = new MyWorker(1,1,"");
      ThreadPool.QueueUserWorkItem(worker.Run);
      

      MSDN page 上有一个等效示例。

      关于在线程池中的线程完成时收到通知,您可以使用WaitHandle 物体内部。大概你不想阻塞,直到线程完成,其中 如果MyWorker 类中的事件、Action 或 Func 将是另一种解决方案。

      我建议阅读有关线程的Joe Albahari's free ebook,因为它更详细地涵盖了这些主题。

      【讨论】:

        猜你喜欢
        • 2020-04-24
        • 1970-01-01
        • 2013-03-23
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 2020-08-19
        • 2010-11-27
        • 1970-01-01
        相关资源
        最近更新 更多