为什么 Thread 比 Parallel.Foreach 更快地打开 OracleConnection?

Why Thread faster than Parallel.Foreach to open OracleConnection?

我有2段代码如下,一段使用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 数据库的连接字符串数组

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

第一次没有创建连接池时

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

我猜单核上的并行 运行ning 应该比线程慢将近 4 倍,谁能解释一下?

谢谢

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

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

在您的第一个示例中,您产生了 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