1

一部の従業員の sql データベースにクエリを実行しています。これらの従業員を受け取ったら、Parallel.ForEach を使用してそれぞれをループします。

データベースから取得した従業員をループしている唯一の理由は、データベースを混乱させたくないいくつかのプロパティを拡張するためです。

この例では、ループ内で現在の従業員のアバターを設定しようとしていますが、常に設定されるのは 3 人中 1 人だけであり、他の従業員のアバターが正しい URI に設定されることはありません。基本的に、アバターのファイル名を取得し、ユーザー フォルダーへのフル パスを作成します。

ここで、設定されている唯一のもののように、各従業員のアバターがディレクトリへのフルパスで更新されない場合、私は何が間違っていますか? 並列スタックと深い 4 つの中にあります

コードのフォーマットが間違っていると確信しています。私はその並列タスクを見てきましたが、6 つのスレッドで 4 つの並列タスクを深く作成しています。

Parallel を使用するようにコードをフォーマットする正しい方法を教えてもらえますか?

また、return await Task.Run()=>GetEmployees メソッドから を削除すると、他のタスクが最初に釣り上げられたため、タスクを終了できないというエラーが発生します。

Parallel は、従業員の 1 人に対してアバターの 1 つだけを設定しているかのように動作しています。

---発信者

   public async static Task<List<uspGetEmployees_Result>> GetEmployess(int professionalID, int startIndex, int pageSize, string where, string equals)
{
    var httpCurrent = HttpContext.Current;

    return await Task.Run(() =>
        {
            List<uspGetEmployees_Result> emps = null;
            try
            {
                using (AFCCInc_ComEntities db = new AFCCInc_ComEntities())
                {
                    var tempEmps = db.uspGetEmployees(professionalID, startIndex, pageSize, where, equals);
                    if (tempEmps != null)
                    {
                        emps = tempEmps.ToList<uspGetEmployees_Result>();

                        Parallel.ForEach<uspGetEmployees_Result>(
                             emps,
                            async (e) =>
                            {
                                e.Avatar = await Task.Run(() => BuildUserFilePath(e.Avatar, e.UserId, httpCurrent, true));
                            }
                         );
                    };
                }
            }
            catch (SqlException ex)
            {
                throw ex;
            };
            return emps;
        });
}

-- 呼び出し先

    static string BuildUserFilePath(object fileName, object userProviderKey, HttpContext context, bool resolveForClient = false)
{
    return string.Format("{0}/{1}/{2}",
                                   resolveForClient ?
                                   context.Request.Url.AbsoluteUri.Replace(context.Request.Url.PathAndQuery, "") : "~",
                                   _membersFolderPath + AFCCIncSecurity.Folder.GetEncryptNameForSiteMemberFolder(userProviderKey.ToString(), _cryptPassword),
                                   fileName.ToString());
}

- - - - - - - - - - - - - - - - - - - - 編集 - - - - - ---------------------------

みんなの助けを借りて使用している最終的なコード。本当にありがとう!

public async static Task<List<uspGetEmployees_Result>> GetEmployess(int professionalID, int startIndex, int pageSize, string where, string equals)
    {
        var httpCurrent = HttpContext.Current;
        List<uspGetEmployees_Result> emps = null;

        using (AFCCInc_ComEntities db = new AFCCInc_ComEntities())
        {

            emps = await Task.Run(() => (db.uspGetEmployees(professionalID, startIndex, pageSize, where, equals) ?? Enumerable.Empty<uspGetEmployees_Result>()).ToList());

            if (emps.Count() == 0) { return null; }
            int skip = 0;
            while (true)
            {
                // Do parallel processing in "waves".
                var tasks = emps
                      .Take(Environment.ProcessorCount)
                      .Select(e => Task.Run(() => e.Avatar = BuildUserFilePath(e.Avatar, e.UserId, httpCurrent, true))) // No await here - we just want the tasks.
                      .Skip(skip)
                      .ToArray();

                if (tasks.Length == 0) { break; }

                skip += Environment.ProcessorCount;
                await Task.WhenAll(tasks);
            };
        }
        return emps;
    }
4

2 に答える 2

2
  1. の定義BuildUserFilePathとその使用法には一貫性がありません。string定義は、それが - を返すメソッドであることを明確に述べていますが、その使用法は、 を返すことを意味しますTask<>
  2. Parallel.ForEach と async はうまく混ざりません。それが最初にバグが発生した理由です。
  3. 無関係ですが、注意する価値があります。try/catchオリジナルを再スローするだけなので、冗長ですSqlException(スタックトレースが失われるため、うまく機能しません)。
  4. あなたは本当に、本当に戻りたいnullですか?

    public async static Task<List<uspGetEmployees_Result>> GetEmployess(int professionalID, int startIndex, int pageSize, string where, string equals)
    {
        var httpCurrent = HttpContext.Current;
    
        // Most of these operations are unlikely to be time-consuming,
        // so why await the whole thing?
        using (AFCCInc_ComEntities db = new AFCCInc_ComEntities())
        {
            // I don't really know what exactly uspGetEmployees returns
            // and, if it's an IEnumerable, whether it yields its elements lazily.
            // The fact that it can be null, however, bothers me, so I'll sidestep it.
            List<uspGetEmployees_Result> emps = await Task.Run(() =>
                (db.uspGetEmployees(professionalID, startIndex, pageSize, where, equals) ?? Enumerable.Empty<uspGetEmployees_Result>()).ToList()
            );
    
            // I'm assuming that BuildUserFilePath returns string - no async.
            await Task.Run(() =>
            {
                Parallel.ForEach(emps, e =>
                {
                    // NO async/await within the ForEach delegate body.
                    e.Avatar = BuildUserFilePath(e.Avatar, e.UserId, httpCurrent, true);
                });
            });
        }
    }
    
于 2013-06-08T03:51:10.613 に答える
1

このコードでは、async と Task.Run() が過剰に使用されているようです。たとえば、このセグメントから何を達成したいと考えていますか?

  Parallel.ForEach<uspGetEmployees_Result>(
                             emps,
                            async (e) =>
                            {
                                e.Avatar = await Task.Run(() => BuildUserFilePath(e.Avatar, e.UserId, httpCurrent, true));
                            }
                         );

メソッド全体の結果に対して既に await を使用しており、a を使用Parallel.ForEachしてループ内の項目の並列実行を取得していawait Task.Run()ます。コードは、それがなくても従うのがはるかに簡単です。

あなたがここで何を達成しようとしているのか、私にははっきりしません。この方法の目的を説明できますか?

于 2013-06-08T02:26:11.207 に答える