使用线程池直接从方法返回对象

时间:2012-06-16 10:09:53

标签: c#

我有这样的方法:

public IOrganizationService GetConnection(bool multi)
        {
            if(!multi)
            {

            Parallel.For(0, 1, i =>
            {
               dynamic _serviceobject= InitializeCRMService();

            });
            }

            else
            {
                ThreadPool.QueueUserWorkItem
                (
                    new WaitCallback
                     (
                         (_) =>
                        {
                            dynamic _serviceobject= InitializeCRMService();

                        }
                     )
                );
            }

        }

我想从方法内部直接返回 _ 服务对象 * *。将两次撤回,即从if和一次撤回一次else循环解决了我的问题。请注意我使用多线程使用Pool线程的概念。如果两个线程并行运行,_serviceobjects将保持唯一。我不会在我的线程之间发生任何交互。

2 个答案:

答案 0 :(得分:2)

WaitCallback内的代码将在线程池中执行,并且可能在GetConnection返回后执行此操作(这是执行异步操作的重点)。因此,由于它是另一个线程(具有另一个调用堆栈)并且它可能会在GetConnection返回后执行,因此您无法从GetConnection内部返回WaitCallback。如果你真的想这样做,那么你必须让GetConnection等到WaitCallback完成执行。 ManualResetEvent可以解决这个问题:

public IOrganizationService GetConnection(bool multi)
{
    var waitHandle = new ManualResetEvent(false);
    dynamic result = null;
    if(!multi)
    {
        Parallel.For(0, 1, i =>
        {
           result = InitializeCRMService();
           waitHandle.Set();
        });
    }
    else
    {
        ThreadPool.QueueUserWorkItem
        (
            new WaitCallback
            (
                (_) =>
                {
                    result = InitializeCRMService();
                    waitHandle.Set();
                }
            )
        );
    }
    //We wait until the job is done...
    waitHandle.WaitOne();
    return result as IOrganizationService; //Or use an adecuate casting
}

但这样做无视首先进行异步操作。由于调用者线程必须等到作业在另一个线程中完成,坐在那里,什么都不做......那么,为什么不同步呢?总之:无意义。

问题是直接返回值是一个同步API。如果你想要异步操作,你需要一个asycrhonous API。如果你有一个异步API,那么你将不得不改变调用者的工作方式。

解决方案包括:

  1. 拥有public property to access the reuslt(选项1)
  2. 拥有callback(选项2)
  3. resourcing to events
  4. 返回任务(或使用async keywork,如果可用)
  5. 返回IObservable(使用Reactive Extensions,如果可用)
  6. 注意:

    1. 拥有puplic属性意味着您需要在调用者中处理syncrhonization。
    2. 有一个回调,意味着一种奇怪的方式来调用该方法,而没有明确的方法来等待。
    3. 使用事件会导致调用者保持订阅事件处理程序的风险。
    4. 由于您正在使用线程池,因此返回任务似乎有点过分。
    5. 在没有Reactive Extension的情况下使用IObservable很容易出错,而且与替代方案相比还有更多的工作。
    6. 就个人而言,我会选择回调选项:

      public void GetConnection(bool multi, Action<IOrganizationService> callback)
      {
          if (ReferenceEquals(callback, null))
          {
              throw new ArgumentNullException("callback");
          }
          if(!multi)
          {
              Parallel.For(0, 1, i =>
              {
                  callback(InitializeCRMService() as IOrganizationService);
                  //Or instead of using "as", use an adecuate casting
              });
          }
          else
          {
              ThreadPool.QueueUserWorkItem
              (
                   new WaitCallback
                   (
                       (_) =>
                       {
                            callback(InitializeCRMService() as IOrganizationService);
                            //Or instead of using "as", use an adecuate casting
                       }
                   )
              );
          }
      }
      

      然后来电者会这样做:

      GetConnection
          (
              false,
              (seriveObject) =>
              {
                  /* do something with seriveObject here */
              }
          );
      //Remember, even after GetConnection completed seriveObject may not be ready
      // That's because it is asyncrhonous: you want to say "hey Bob do this for me"
      // and you can go do something else
      // after a while Bob comes back an says:
      // "that thing you asked me to do? well here is the result".
      // We call that a callback, and the point is that you didn't have to wait for Bob
      // you just kept doing your stuff...
      //So... when is seriveObject ready? I don't know.
      //But when seriveObject is ready the callback will run and then you can use it
      

答案 1 :(得分:1)

您无法从WaitCallback处理程序内部返回它,因为代码中没有人将其返回。那只是一个回调。 您可能想尝试定义一个具有动态成员的自定义事件(派生自EventArgs)。

然后,您可以从工作人员入口点引发此事件,并随之发送动态对象。

您可以根据需要绑定到事件(即您要使用动态对象的位置)。

编辑(也显示一些代码):

在您拥有GetConnection方法的同一个类中,还要定义一个事件:

internal event EventHandler<SomeEventArgs> OnWorkerFinished = (s, e) => {};

然后,定义项目中的某个地方(靠近这个类),SomeEventArgs类:

internal class SomeEventArgs : EventArgs 
{
  public dynamic WorkerResult { get; private set; }

  public SomeEventArgs(dynamic workerResult) 
  {
    WorkerResult = workerResult;
  }
}

接下来,在工人中:

 new WaitCallback
 (
    (_) =>
    {
      dynamic _serviceobject= InitializeCRMService();
     //Here raise the event
     SomeEventArgs e = new SomeEventArgs(_serviceObject);
     OnWorkerFinished(this, e);
    }
 )

我不知道你想用什么来获取结果,但是在那个地方你应该绑定到这个类的OnWorkerFinished事件(你有GetConnectionMethod)。