2

我在 C# 程序中有以下 PLINQ 语句:

 foreach (ArrestRecord arrest in
            from row in arrestQueue.AsParallel()
            select row)
        {
            Geocoder geocodeThis = new Geocoder(arrest);
            writeQueue.Enqueue(geocodeThis.Geocode());
            Console.Out.WriteLine("Enqueued " + ++k);
        }

两者都是ConcurrentQueuesarrestQueue_writeQueue

没有并行运行:

  • 运行时,总 CPU 使用率约为 30%,这也是所有其他运行的情况。我有 8 个内核(具有 4 个物理内核的 Core i7 720QM 上的超线程),8 个内核中有 4 个几乎没有任何利用率。其余的运行大约 40%-50%。
  • 磁盘使用率通常为 0%,除了查询本地主机上的 Postgres 数据库外,没有网络使用情况(见下文)。
  • 如果我在内部某处添加断点geocodeThis.Geocode(),Visual Studio 的Thread下拉列表只会显示[ pid ] Main Thread。它永远不会进入任何其他线程。
  • 我正在使用Npgsql连接到 Postgres,并且每个线程对一个表运行一些SELECT查询。我正在运行 pgAdmin III 的服务器状态应用程序,它显示pg_stat_activity。通过监控这一点,以及战略断点放置(见上文),我可以看到应用程序永远不会为所有假定的并发线程打开超过 1 个数据库连接geocodeThis.Geocode()。即使我将Pooling=false添加到数据库连接字符串中,以强制连接不被池化,我也从未看到超过 1 个连接在geocodeThis.Geocode().
  • Postgres 表在WHERE子句中的每一列上都有索引。即使它的索引很差,我也希望有大量的磁盘使用。如果 Postgres 以任何其他方式支撑事情,似乎它会吸收核心。

这似乎是一个简单的 PLINQ 案例研究,我正在为为什么没有并行运行而摸不着头脑。

4

2 回答 2

5

您只是将assertQueue自身的枚举并行化,然后将其“非并行化”回普通的IEnumerable. 这一切都发生在foreach循环开始之前。然后你使用普通IEnumerable的 withforeach串行运行循环体。

有很多方法可以并行运行循环体,但首先想到的是使用Parallel.ForEach

Parallel.ForEach(arrestQueue, arrest =>
    {
        Geocoder geocodeThis = new Geocoder(arrest);
        writeQueue.Enqueue(geocodeThis.Geocode());
        Console.Out.WriteLine("Enqueued " + ++k);
    });
于 2011-05-22T04:59:50.083 回答
1

对并行集合的 foreach 仍然是单线程操作。.AsParallel 返回一个定义 .ForAll 方法的集合,该方法可以(但根据合同并不总是)并行运行。代码是:

arrestQueue.AsParallel().ForAll(arrest=>
    {
        Geocoder geocodeThis = new Geocoder(arrest);
        writeQueue.Enqueue(geocodeThis.Geocode());
        Console.Out.WriteLine("Enqueued " + ++k);
    });
于 2011-05-22T04:59:24.220 回答