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 *を直接*返したいです。2回再試行します。つまり、ifから1回、elseループから1回で問題が解決します。プールスレッドの概念を使用してマルチスレッドを使用していることに注意してください。_serviceobjectsは残りますか? 2つのスレッドが並行して実行されている場合に固有です。スレッド間で相互作用が発生することはありません。

4

2 に答える 2

2

の内部のコードWaitCallbackはスレッド プールで実行され、おそらくGetConnectionが戻った後に実行されます (これが非同期操作を実行するポイントです)。したがって、これは別のスレッド (別のコール スタックを持つ) であり、 が戻った後に実行される可能性があるため、 の内部から戻るGetConnectionことはできません。本当にそれをしたい場合は、 の実行が完了するまで待機する必要があります。ManualResetEvent はトリックを実行できます。GetConnectionWaitCallbackGetConnectionWaitCallback

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 を返す (利用可能な場合は Reactive Extensions を使用)

ノート:

  1. public プロパティを持つということは、呼び出し元で同期を処理する必要があることを意味します。
  2. コールバックがあるということは、メソッドを呼び出す奇妙な方法であり、明示的に待機する方法がないことを意味します。
  3. イベントを使用すると、呼び出し元がイベント ハンドラーにサブスクライブされたままになるリスクがあります。
  4. スレッドプールを使用しているため、タスクを返すのはやり過ぎのようです。
  5. Reactive Extension を使用せずに 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 に答える