Parallel.ForEach没有设置在环路中的所有值 [英] Parallel.ForEach not setting all values in loop

查看:472
本文介绍了Parallel.ForEach没有设置在环路中的所有值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我查询了一些员工一个SQL数据库。
当我收到这些员工我和循环每一个使用Parallel.ForEach。

我在循环被从数据库中检索他的员工是这样展开一些,我不希望扰乱与数据库属性的唯一原因。

从不最少在这个例子中,我试图设置的阿凡达在循环中的当前员工,但三只一出总是被设置,没有其他员工头像曾经被设置为正确的URI。基本上,我走的是化身的文件名和建设的完整路径用户文件夹。

我在做什么错在这里,每个员工不更新的完整路径的目录阿凡达一样,被设置的唯一一个?并行堆栈并且在深4

我敢肯定,我已经得到了格式不正确的code。我看着那个并行任务,它并深6线程创建4个并行任务。

有人能指出我格式化code使用并行的正确方法?

此外,有一件事,如果我删除返回等待Task.Run()=> 从getEmployees方法,我得到的不能完成的任务,因为其他一些错误任务首先捕捞。

并行充当如果只设置化身的一个用于雇员之一

---来电

 公共异步静态任务<名单,LT; uspGetEmployees_Result>> GetEmployess(INT professionalID,诠释了startIndex,诠释的pageSize,字符串,其中,字符串等于)
{
    VAR httpCurrent = HttpContext.Current;    返回等待Task.Run(()=>
        {
            清单< uspGetEmployees_Result> EMPS = NULL;
            尝试
            {
                使用(AFCCInc_ComEntities DB =新AFCCInc_ComEntities())
                {
                    VAR tempEmps = db.uspGetEmployees(professionalID,则startIndex,pageSize的,在那里,等于);
                    如果(tempEmps!= NULL)
                    {
                        EMPS = tempEmps.ToList< uspGetEmployees_Result>();                        Parallel.ForEach< uspGetEmployees_Result>(
                             EMPS,
                            异步(E)=>
                            {
                                e.Avatar =等待Task.Run(()=> BuildUserFilePath(e.Avatar,e.UserId,httpCurrent,真实));
                            }
                         );
                    };
                }
            }
            赶上(SQLEXCEPTION EX)
            {
                扔恩;
            };
            返回EMPS;
        });
}

- 被叫

 静态字符串BuildUserFilePath(目标文件名,对象userProviderKey,HttpContext的背景下,布尔resolveFor​​Client = FALSE)
{
    返回的String.Format({0} / {1} / {2},
                                   resolveFor​​Client?
                                   context.Request.Url.AbsoluteUri.Replace(context.Request.Url.PathAndQuery,):〜,
                                   _membersFolderPath + AFCCIncSecurity.Folder.GetEncryptNameForSiteMemberFolder(userProviderKey.ToString(),_cryptPassword),
                                   fileName.ToString());
}

----------------------------------------编辑------ ------------------------------

最后code,我使用大家的帮助。非常感谢!

 公共异步静态任务<名单,LT; uspGetEmployees_Result>> GetEmployess(INT professionalID,诠释了startIndex,诠释的pageSize,字符串,其中,字符串等于)
    {
        VAR httpCurrent = HttpContext.Current;
        清单< uspGetEmployees_Result> EMPS = NULL;        使用(AFCCInc_ComEntities DB =新AFCCInc_ComEntities())
        {            的emps =等待Task.Run(()=>(db.uspGetEmployees(professionalID,则startIndex,pageSize的,其中,等于)?? Enumerable.Empty&所述; uspGetEmployees_Result方式>())了ToList());            如果(emps.Count()== 0){返回NULL; }
            INT跳过= 0;
            而(真)
            {
                //在浪做并行处理。
                VAR任务= EMPS
                      。取(Environment.ProcessorCount)
                      。选择(E => Task.Run(()=> e.Avatar = BuildUserFilePath(e.Avatar,e.UserId,httpCurrent,真实)))//没有等候在这里 - 我们只是想的任务。
                      .Skip(跳过)
                      .ToArray();                如果(tasks.Length == 0){打破; }                跳过+ = Environment.ProcessorCount;
                等待Task.WhenAll(任务);
            };
        }
        返回EMPS;
    }


解决方案

  1. BuildUserFilePath 的定义及其用法不一致。该定义明确指出,这是一个字符串 -returning方法,而它的使用意味着它返回一个任务<>

  2. Parallel.ForEach和异步不要混用很好 - 这就是你的错误发生在首位的原因

  3. 无关,但仍值得注意:你的的try / catch 是多余的,因为它是所有重新抛出原来的的SQLException (即使它没有做的非常好,因为你最终输掉了堆栈跟踪)。

  4. 你真的,的真正的想回到

     公共异步静态任务<名单,LT; uspGetEmployees_Result>> GetEmployess(INT professionalID,诠释了startIndex,诠释的pageSize,字符串,其中,字符串等于)
    {
        VAR httpCurrent = HttpContext.Current;    //大多数这些操作不太可能费时,
        //所以为什么等待整个事情?
        使用(AFCCInc_ComEntities DB =新AFCCInc_ComEntities())
        {
            //我真的不知道究竟uspGetEmployees回报
            //并且,如果它是一个IEnumerable,无论它产生的元素懒洋洋地。
            //,它可以是空的事实,然而,困扰我,所以我会回避它。
            清单< uspGetEmployees_Result> EMPS =等待Task.Run(()=>
                (db.uspGetEmployees(professionalID,则startIndex,pageSize的,在那里,等于)?? Enumerable.Empty< uspGetEmployees_Result>())。了ToList()
            );        //我假设BuildUserFilePath返回字符串 - 没有异步。
            等待Task.Run(()=>
            {
                Parallel.ForEach(EMPS,E =>
                {
                    //没有异步/等待的ForEach委托体内。
                    e.Avatar = BuildUserFilePath(e.Avatar,e.UserId,httpCurrent,真正的);
                });
            });
        }
    }


I am querying a sql data base for some employees. When i receive these employees I and looping each one using the Parallel.ForEach.

The only reason I'm looping he employees that was retrieved from the database is so expand a few of the properties that I do not want to clutter up the data base with.

Never-the-less in this example I am attempting to set the Avatar for the current employee in the loop, but only one out of three always gets set, none of the other employees Avatar ever gets set to their correct URI. Basically, I'm taking the file-name of the avatar and building the full path to the users folder.

What am I doing wrong here to where each employees Avatar is not updated with the full path to their directory, like the only one that is being set? Parallel stack and there is in deep four

I'm sure I've got the code formatted incorrectly. I've looked at that Parallel Task and it does in deep create 4 Parallel Task on 6 Threads.

Can someone point out to me the correct way to format the code to use Parallel?

Also, one thing, if I remove the return await Task.Run()=> from the GetEmployees method I get an error of cannot finish task because some other task fished first.

The Parallel is acting as if it is only setting one of the Avatars for one of the employees.

---Caller

   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;
        });
}

--Callee

    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());
}

----------------------------------------Edit------------------------------------

The final code that I'm using with everyone's help. Thanks so much!

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;
    }

解决方案

  1. Your definition of BuildUserFilePath and its usage are inconsistent. The definition clearly states that it's a string-returning method, whereas its usage implies that it returns a Task<>.
  2. Parallel.ForEach and async don't mix very well - that's the reason your bug happened in the first place.
  3. Unrelated but still worth noting: your try/catch is redundant as all it does is rethrow the original SqlException (and even that it doesn't do very well because you'll end up losing the stack trace).
  4. Do you really, really want to return 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);
                });
            });
        }
    }
    

这篇关于Parallel.ForEach没有设置在环路中的所有值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆