为什么 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.30GHz
与 16GB RAM
、来自 nuget 的 Oracle.ManagedDataAccess 库中的 OracleConnection 一起使用。
第一次没有创建连接池时
Thread approach
:所有线程在 运行 后 3 到 5 秒停止
Parallel approach
:平行停止在运行 后12到15秒
下一次,两种方法的结果相似,因为创建了连接池。
我猜单核上的并行 运行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
我有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.30GHz
与 16GB RAM
、来自 nuget 的 Oracle.ManagedDataAccess 库中的 OracleConnection 一起使用。
第一次没有创建连接池时
Thread approach
:所有线程在 运行 后 3 到 5 秒停止
Parallel approach
:平行停止在运行 后12到15秒
下一次,两种方法的结果相似,因为创建了连接池。
我猜单核上的并行 运行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