1

我有这样的方法:

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

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

            });
            }

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

                        }
                     )
                );
            }

        }

我想从方法内部直接返回_serviceobject * 。将返回它两次,即一次从if 和一次从else 循环解决我的问题。请注意,我使用的是使用池线程概念的多线程。_serviceobjects 会保留在两个线程并行运行的情况下是独一无二的。我不希望我的线程之间发生任何交互。

4

2 回答 2

2

内部的代码WaitCallback将在线程池中执行,并且可能在GetConnection返回后执行(这就是执行异步操作的重点)。因此,由于它是另一个线程(具有另一个调用堆栈)并且它可能会在GetConnection返回后执行,因此您不能GetConnectionWaitCallback. 如果你真的想这样做,那么你将不得不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。如果您想要异步操作,您将需要一个异步 API。如果您将有一个异步 API,那么您将不得不改变调用者的工作方式。

解决方案包括:

  1. 拥有访问 reuslt 的公共财产(选项 1)
  2. 回调(选项 2)
  3. 为活动提供资源
  4. 返回一个任务(或使用异步密钥,如果可用)
  5. 返回 IObservable(如果可用,使用响应式扩展)

笔记:

  1. 拥有公共属性意味着您将需要处理调用者中的同步。
  2. 有一个回调,意味着调用该方法的一种奇怪的方式,并且没有明确的等待方式。
  3. 使用事件有调用者保持订阅事件处理程序的风险。
  4. 由于您使用的是线程池,因此返回任务似乎有点过头了。
  5. 使用没有响应式扩展的 IObservable 很容易出错,并且与替代方案相比,工作量要大得多。

我个人会选择回调选项:

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
于 2012-06-16T22:37:35.637 回答
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)。

于 2012-06-16T10:21:07.483 回答