【问题标题】:Rewriting foreach using IObservable and Reactive Framework使用 IObservable 和 Reactive Framework 重写 foreach
【发布时间】:2010-02-04 17:23:25
【问题描述】:

我在 VS2008 中使用实体框架。我正在使用 esql 访问数据库中的对象以获得 WHERE IN 功能。我将大量 ID 传递给 select 语句,因此我将其分成 800 个组。然后我将每个块的结果合并在一起。我的目标是并行获取每个块的结果,而不是同步等待。我安装了 Reactive Framework,并且很确定我需要使用 ForkJoin。但是,我不知道如何转换这个函数来使用它。这是我现有的代码:

    public static IList<TElement> SelectWhereIn<TElement, TValue>(this ObjectContext context, string fieldName, IList<TValue> idList)
    {
        var chunkedIds = idList.Split(CHUNK_SIZE);
        string entitySetName = typeof(TElement).Name + "Set";
        var retList = new List<TElement>();
        foreach (var idChunk in chunkedIds)
        {
            string delimChunk = string.Join(",", idChunk.Select(x => x.ToString()).ToArray());
            ObjectQuery<TElement> query = context.CreateQuery<TElement>("SELECT VALUE x FROM " + entitySetName + " AS x");
            query = query.Where("it." + fieldName + " IN {" + delimChunk + "}");
            retList.AddRange(query);
        }
        return retList;
    }

谢谢!

编辑 >>> 我修改了代码以使用Poor Man,如下所示:

    public static IList<TElement> SelectWhereIn<TElement, TValue>(this ObjectContext context, string fieldName, IList<TValue> idList)
    {
        var chunkedIds = idList.Split(CHUNK_SIZE);
        string entitySetName = typeof(TElement).Name + "Set";
        var chunkLists = new List<IEnumerable<TElement>>();
        Parallel.ForEach(chunkedIds, idChunk =>
        {
            string delimChunk = string.Join(",", idChunk.Select(x => x.ToString()).ToArray());
            ObjectQuery<TElement> query = context.CreateQuery<TElement>("SELECT VALUE x FROM " + entitySetName + " AS x");
            query = query.Where("it." + fieldName + " IN {" + delimChunk + "}");
            chunkLists.Add(query.ToList());
        });
        var retList = new List<TElement>();
        foreach (var chunkList in chunkLists)
        {
            retList.AddRange(chunkList);
        }
        return retList;
    }

第一次效果很好。但是我第二次运行它时,我得到了这个错误:

连接没有关闭。连接的当前状态是正在连接。 说明:执行当前 Web 请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.InvalidOperationException:连接未关闭。连接的当前状态为正在连接。

来源错误:

第 49 行:foreach(结果列表中的变量 iAsyncResult) 第 50 行:{ 第 51 行:del.EndInvoke(iAsyncResult); 第 52 行:iAsyncResult.AsyncWaitHandle.Close(); 第 53 行:}

有趣的是,b/c Emre(该库的作者)对他的原始帖子进行了编辑,讨论了他如何添加这些代码行以增加安全性。我用对了吗?还是他的 v1 更安全?

【问题讨论】:

  • 嗯,您是否要创建并行 foreach ? “我的目​​标是并行获取每个块的结果,而不是同步等待”。这就是我要说的
  • 是的,完全正确。一个平行的foreach。我知道 VS2010 正在开发这个,并且有一个叫做 Parallel Extensions 的东西(因为被 MSFT 撤回了)。所以我对 VS2008 的最大希望似乎是我正在前进的道路,或者可能使用这个tomasp.net/blog/csharp-async.aspx。但我无法让任何一个工作都完全正确。或者,当然,如果您有其他想法……谢谢。
  • 嗯,听起来你需要不同的上下文,请查看我的编辑了解更多详情

标签: c# asynchronous system.reactive


【解决方案1】:

VS2010 确实具有 PLINQ 的功能。使用扩展 AsParallel().WithDegreeOfParallelism(nbProcessors) 可以满足您的需求。

对于 VS2008,我过去在尝试解决性能瓶颈时使用过 Poor Man's Parallel.ForEach Iterator by Emre Aydinceren,尝试尝试一下。

编辑:作为对您添加的错误的反应,它可能是在黑暗中随机拍摄,但每个线程都有单独的上下文?像这样:

Parallel.ForEach(chunkedIds, idChunk =>
    {
        ObjectContext context = new MyContext(connStr);//depending what's your config
                                                       // like, with or w/o conn string

        string delimChunk = string.Join(",", idChunk.Select(x => x.ToString()).ToArray());
        ObjectQuery<TElement> query = context.CreateQuery<TElement>("SELECT VALUE x FROM " + entitySetName + " AS x");
        query = query.Where("it." + fieldName + " IN {" + delimChunk + "}");
        chunkLists.Add(query.ToList());
    });

您可能需要调整一些事情(例如从扩展的上下文中获取连接字符串以实例化新上下文)。

【讨论】:

  • 肯定会到达那里。这是有希望的。它第一次工作,但是当我第二次运行它时,它崩溃了。由于 cmets 无法保存代码,我将发布一个带有详细信息的“答案”。
  • 我的上下文只是我用于所有存储库功能的实体框架上下文。
  • 呃哦...起初它有效,但现在我似乎遇到了一个新问题。 “无法定义两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象。”
  • 几周前我忘了更新这个,但我只想说......我意识到我试图通过 Linq 进行批量导入/更新操作来运行一个兔子洞实体而不是直接在 SQL Server 中。
猜你喜欢
  • 2014-06-17
  • 2021-09-16
  • 2016-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
相关资源
最近更新 更多