0

会社の CRM ソリューション (Oracle's Right Now) で 60 万人のユーザーを照会し、存在する場合は更新するか、存在しない場合は作成する必要があります。ユーザーが Right Now に既に存在するかどうかを確認するために、サード パーティの WS を使用します。また、60 万人のユーザーの場合、応答を取得するたびに時間がかかるため (約 1 秒)、これは非常に苦痛になる可能性があります。そのため、コードを使用するように変更し、Parallel.ForEach各レコードをわずか 0.35 秒でクエリし、それをList<User>作成または更新するレコードの に追加しました (今はちょっとばかげているので、それらを 2 つのリストに分けて、 2 つの異なる WS メソッドを呼び出します)。

私のコードは、マルチスレッドの前に完全に実行されていましたが、時間がかかりすぎました。問題は、バッチを大きくしすぎたり、Web サービスを介して更新または作成しようとするとタイムアウトになることです。そのため、一度に約 500 件のレコードを送信しています。重要なコード部分を実行すると、何度も実行されます。

Parallel.ForEach(boDS.USERS.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = -1 }, row =>
{
    ...
    user = null;
    user = QueryUserById(row["USER_ID"].Trim());

    if (user == null)
    {
        isUpdate = false;
        gObject.ID = new ID();
    }
    else
    {
        isUpdate = true;
        gObject.ID = user.ID;
    }

    ... fill user attributes as generic fields ...

    gObject.GenericFields = listGenericFields.ToArray();

    if (isUpdate)
        listUserUpdate.Add(gObject);
    else
        listUserCreate.Add(gObject);

    if (i == batchSize - 1 || i == (boDS.USERS.Rows.Count - 1))
    {               
        UpdateProcessingOptions upo = new UpdateProcessingOptions();
        CreateProcessingOptions cpo = new CreateProcessingOptions();
        upo.SuppressExternalEvents = false;
        upo.SuppressRules = false;
        cpo.SuppressExternalEvents = false;
        cpo.SuppressRules = false;

        RNObject[] results = null;

        // <Critical_code>

        if (listUserCreate.Count > 0)
        {
            results = _service.Create(_clientInfoHeader, listUserCreate.ToArray(), cpo);
        }
        if (listUserUpdate.Count > 0)
        {
            _service.Update(_clientInfoHeader, listUserUpdate.ToArray(), upo);
        }
        // </Critical_code>

        listUserUpdate = new List<RNObject>();
        listUserCreate = new List<RNObject>();
    }
    i++;
});

lockorを使用することを考えましmutexたが、後で実行されるのを待つだけなので、役に立ちません。コードの一部のスレッドで1回だけ実行するための解決策が必要です。出来ますか?誰かが光を共有できますか?

よろしくお願いします、 レアンドロ

4

2 に答える 2

0

コメントで述べたように、ループ本体の外側で変数を宣言しています。それがあなたの競合状態の起源です。

listUserUpdate変数を例にとってみましょう。並列実行スレッドによってランダムにアクセスされます。1 つのスレッドがまだ追加されている間、たとえば、listUserUpdate.Add(gObject);別のスレッドですでに のリストをリセットlistUserUpdate = new List<RNObject>();または列挙している可能性がありますlistUserUpdate.ToArray()

あなたは本当にそのコードをリファクタリングする必要があります

  • ループ本体内で変数を移動することにより、各ループを可能な限り互いに独立して実行し、
  • ロックおよび/または同時収集を使用して同期する方法でデータにアクセスする
于 2014-07-23T22:34:32.197 に答える