5

いくつかのサードパーティAPIを検索するコードがあります。検索条件に基づいて、検索を2つのグループに分けています。各検索は非常にタイムリーであるため、両方の検索を開始しますが、最初の検索グループが一致した場合、2番目の検索グループが終了するのを待ちたくありません。つまり、基本的に私が持っているのは次のとおりです。

Dictionary<string, string> result = null;
NameSearchDelegate nameDel = new NameSearchDelegate(SearchByName);
IAsyncResult nameTag = nameDel.BeginInvoke(name, null, null);
if(!string.IsNullOrWhiteSpace(telNum))
{
    result = SearchByTelNum(telNum);//Will return null if a match is not found
}
if(null == result)
{
    result = nameDel.EndInvoke(nameTag);
}
//End the delegate to prevent memory leak
//else
//{
//    nameDel.EndInvoke(nameTag)
//}
return result;

したがって、一致が見つからない場合に備えてSearchByTelNumを呼び出す前にSearchByNameを開始したいのですが、一致が見つかった場合は、SearchByNameが終了するのを待ってから一致を返す必要はありません。結果が不要になった場合に、そのデリゲートを単に終了またはキャンセルする方法はありますか?

4

2 に答える 2

1

System.ComponentModel.BackgroundWorkerを使用して問題を解決することができました。本来の使い方とは限りませんでしたが、必要なことはできました。つまり、基本的に私の新しいコードは次のようになります。

Dictionary<string, string> telResult = null,
                           nameResult = null;

BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (obj, e) => nameResult = SearchByName(name, bw);
bw.RunWorkerAsync();

if(!string.IsNullOrWhiteSpace(telNum))
    telResult = SearchByTelNum(telNum);//Will return null if a match is not found

if(telResult != null)
{
    bw.CancelAsync;
    return telResult;
}

bool hasTimedOut = false;
int i = timeOutCount;
while (bw.IsBusy && !hasTimedOut)
{
    System.Threading.Thread.Sleep(500);
    if (0 == --i) hasTimedOut = true;
}

return nameResult;

また、バグがないことを確認するために、SearchByNameが定期的にbw.CancellationPendingがtrueに等しいかどうかを確認し、その場合はメソッドを終了する必要がありました。CancelAsyncはワーカースレッドを終了せず、呼び出し元のスレッドがそれをキャンセルしたことをワーカースレッドに警告するだけです。

また、私は単に使用することができました

while(bw.IsBusy) System.Threading.Thread.Sleep(500)

メソッドが完了するのを待ちますが、SearchByNameで何か問題が発生した場合、無限ループで永遠に待つことになります。このようにして、メソッドがタイムアウトしたと見なされ、呼び出し元のスレッドが存続するまでの時間を設定できます。この場合、0.5秒ごとにbw.IsBusyをチェックするため、タイムアウトの長さはtimeOutCount/2秒に等しくなります。

わかりました、私は自分の質問に徹底的に答えたと思います。

于 2013-02-04T15:58:01.620 に答える
0

中止可能なパラメータオブジェクトを定義することでこれを処理しました

public class AbortableParameter<T>
{
    public T Parameter { get; private set }
    public bool ShouldAbort { get; set; }
    public AbortableParameter(T parameter)
    {
        Parameter = parameter;
        ShouldAbort = false;
    }
}

デリゲートに渡したいパラメータを使用してこのクラスのインスタンスを作成し、それへの参照を保持するだけです。デリゲートを終了する必要がある場合は、trueに設定します。次に、デリゲートは定期的にチェックShouldAbortして、になったら正常に終了する必要がありtrueます。

これは欠点です。代理人は定期的にチェックする必要があります。そうしないと、中止するかどうかは関係ありません。

プロパティのsetメソッドがtrueに設定されている場合にデリゲートを強制終了することも可能ShouldAbortですが、これは適切な終了ではなく、ほとんどの場合回避する必要があります。ただし、デリゲートのポーリングを必要としないという利点があります。

于 2013-01-30T04:44:55.923 に答える