c# - 递归和 Rx 并行性

标签 c# multithreading performance parallel-processing system.reactive

在尝试高效地遍历目录树时,我尝试了一个描述为 here 的 RX 解决方案.虽然此解决方案适用于小树深度,但不适用于大树深度。默认调度程序创建了太多线程,从而减慢了树遍历。

这是我使用的代码:

public static void TestTreeTraversal()
    {
        Func<DirectoryInfo, IObservable<DirectoryInfo>> recurse = null;
        recurse = i => Observable.Return(i)
                        .Concat(i.GetDirInfos().ToObservable().SelectMany(d => recurse(d)))
                        .ObserveOn(Scheduler.Default);
        var obs = recurse(new DirectoryInfo(@"C:\"));
        var result = obs.ToEnumerable().ToList();
    }

public static IEnumerable<DirectoryInfo> GetDirInfos(this DirectoryInfo dir)
    {
        IEnumerable<DirectoryInfo> dirs = null;
        try
        {
            dirs = dir.EnumerateDirectories("*", SearchOption.TopDirectoryOnly);
        }
        catch (Exception)
        {
            yield break;
        }
        foreach (DirectoryInfo d in dirs)
            yield return d;
    }

如果删除 ObserveOn(Scheduler.Default),该函数的运行速度与单线程递归函数相同。使用 ObserveOn,似乎每次调用 SelectMany 时都会创建一个线程,从而显着减慢进程。

有没有办法控制/限制调度器可以同时使用的最大线程数?

有没有另一种方法可以用 Rx 编写这样的并行树遍历,而不会陷入这种并行陷阱?

最佳答案

它可以在 Rx 中用 this overload of the Merge operator 完成,也许通过传递 Environment.ProcessorCountmaxConcurrent参数。

然而,Rx 被设计用来处理 IObservable<T>用于 native 异步处理。当然你可以转换 IEnumerable<T>进入 IObservable<T>并并行处理它,就像您在此处所做的那样,但这与 Rx 中的规则背道而驰。

这个问题更自然的解决方案是 PLINQ , 以 IEnumerable<T> 开头并且设计用于将查询划分为并行进程,隐含地考虑可用物理处理器的数量。

Rx 主要是关于驯服并发性,而 PLINQ 主要是关于引入并发性。

未测试:

Func<DirectoryInfo, ParallelQuery<DirectoryInfo>> recurse = null;

recurse = dir => new[] { dir }.AsParallel()
  .Concat(dir.GetDirInfos().AsParallel().SelectMany(recurse));

var result = recurse(new DirectoryInfo(@"C:\")).ToList();

关于c# - 递归和 Rx 并行性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28090216/

相关文章:

c# - 在 asp.net Web 应用程序中使用 jQuery 表替换 GridView?

c# - 更改本地 Windows 用户的密码

java - 线程堆栈的内部 Java 内存模型

c - 多线程 C 代码在编译器优化下会崩溃,如果没有编译器优化,则可以完美运行,这是预期会发生的情况,还是肯定是一个错误?

git - SourceTree 非常慢,有很多存储库

java - 通过删除重复的 BufferedImages/在 Java 中比较 BufferedImages 的快速方法来优化性能

c# - 与 C++ 相比,我对 C# 中的引用传递的工作方式是否正确?

c# - ASP.NET Core GZIP 编码中间件仅在添加两次后才有效

c# - DoEvents 与其他任何东西 --> 对于长时间的 COM 操作

performance - 与数据 View 相比,Linq 到对象的速度非常慢