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

时间:2018-01-04 11:53:01

标签: c# multithreading oracle ado.net task-parallel-library

我有两段代码如下,一个使用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倍,有人可以解释一下吗?

谢谢

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

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