为什么线程比Parallel.Foreach更快打开OracleConnection?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么线程比Parallel.Foreach更快打开OracleConnection?相关的知识,希望对你有一定的参考价值。

我有两段代码如下,一个使用Thread,一个使用Parallel.Foreach

线

foreach (var i in new int [] {0, 1, 2, 3, 4, ..., 24 })
    new Thread(GET_DATA).Start(i);

平行

Parallel.Foreach(new int [] {0, 1, 2, 3, 4, ..., 24 }, GET_DATA);

使用方法GET_DATA

void GET_DATA(object state) {
    var x = (int)state;

    using (var conn = new OracleConnection(cs[x])) {
        conn.Open();
        using (var cmd = conn.CreateCommand()) {
            cmd.CommandText = "select * from dual";
            var dt = new DataTable();
            dt.Load(cmd.ExecuteReader());
        }
    }
}

和cs是25 Oracle Database的连接字符串数组

我使用Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz16GB RAM,来自nuget的Oracle.ManagedDataAccess库中的OracleConnection。

第一次,没有创建连接池时

  • Thread approach:所有线程在运行后3到5秒停止
  • Parallel approach:跑步后12至15秒平行停止

在下一次,两种方法的结果相似,因为创建了连接池。

我想在单核上并行运行应该比线程慢近4倍,任何人都能解释一下吗?

谢谢

答案

在第一个示例中,您生成了24个线程,它们将通过等待I / O操作(建立与数据库的套接字连接)来完成。

在第二个示例中,您使用未知数量的线程(取决于核心数和并行化设置的程度)来处理24个项目的列表。每个线程将以串行方式处理项目的子集。

由于操作在您的进程中不受CPU限制,而是依赖于外部进程(数据库的I / O,数据库上的操作等),Parallel.Foreach将浪费大量时间等待一个任务完成之前开始下一个。

X是操作的完成,时间是垂直的,线程是水平的。

使用24个线程时:

1 2 3 ... 24   Time
| | |      |    |
| | |      |    |
| | |      |    |
| | |      |    |
| | |      |    |
X X X      X    V

使用4个线程处理24个项目时:

1 2 3 4   Time
| | | |    |    
| | | |    |    
| | | |    |    
X X X X    |    
| | | |    |
| | | |    |
| | | |    |
X X X X    |
| | | |    |
| | | |    |
| | | |    |
X X X X    |
. . . .    |
. . . .    |
. . . .    V
另一答案
Parallel.Foreach(new int [] {0, 1, 2, 3, 4, ..., 24 }, GET_DATA);

还请将此添加到Parallel.Foreach以使两个样本使用相同数量的线程。

new ParallelOptions { MaxDegreeOfParallelism = 24 }

至于正常的foreach,这将在退出循环之前等待所有线程完成

foreach (var i in new int [] {0, 1, 2, 3, 4, ..., 24 })
    new Thread(GET_DATA).Start(i);

如果等待所有线程完成,我相信你会得到相同的结果。

以上是关于为什么线程比Parallel.Foreach更快打开OracleConnection?的主要内容,如果未能解决你的问题,请参考以下文章

Parallel.ForEach 没有提供更多内核的加速[关闭]

Parallel.ForEach 比 ForEach 慢

计算 Parallel.ForEach 使用的线程数

强制终止由 Parallel.ForEach 生成的线程 [重复]

C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比预期的少

更新 Parallel.ForEach 线程中对象的属性是不是安全?