多线程阅读会导致性能低下吗?

时间:2015-09-25 13:01:16

标签: multithreading sqlite

我将代码写入选择并发3个线程,并使用单线程一连接;我发现它比1线程慢;

以下是我的测试数据:
它是一个包含100000个项目的表(索引uint32);

当我在3个帖子中选择 100000个项目(所有项目)时:

0: 1443185531.782627, info: <NSThread: 0x13f99ac40>{number = 4, name = (null)} read ready
1: 1443185531.782634, cost 0.000007, info: <NSThread: 0x13f99ac40>{number = 4, name = (null)} read start
2: 1443185533.365550, cost 1.582916, info: <NSThread: 0x13f99ac40>{number = 4, name = (null)} read end

0: 1443185531.772624, info: <NSThread: 0x13f871e60>{number = 2, name = (null)} read ready
1: 1443185531.782659, cost 0.010035, info: <NSThread: 0x13f871e60>{number = 2, name = (null)} read start
2: 1443185533.372972, cost 1.590313, info: <NSThread: 0x13f871e60>{number = 2, name = (null)} read end

0: 1443185531.773191, info: <NSThread: 0x13f99a6a0>{number = 3, name = (null)} read ready
1: 1443185531.782636, cost 0.009445, info: <NSThread: 0x13f99a6a0>{number = 3, name = (null)} read start
2: 1443185533.393716, cost 1.611080, info: <NSThread: 0x13f99a6a0>{number = 3, name = (null)} read end

你可以看到平均成本是1.5 但是当我在1个主题中更改为选择 100000个项目(所有项目)时:

0: 1443185738.427020, info: <NSThread: 0x14d970990>{number = 2, name = (null)} read ready
1: 1443185738.427106, cost 0.000086, info: <NSThread: 0x14d970990>{number = 2, name = (null)} read start
2: 1443185739.020410, cost 0.593304, info: <NSThread: 0x14d970990>{number = 2, name = (null)} read end

成本达到0.5秒。

所以我很困惑,多线程读取会降低sqlite3的性能。

据我所知,读取使用shared-mutex,它可以在多线程中共享。不应该发生性能下降。

有人能解决我的困惑吗?

附加:
sqlite3处于WAL,SQLITE_CONFIG_MULTITHREAD模式,没有任何手动互斥。

附加:
我以这种方式在3个线程中运行我的代码。

//objc code
dispatch_async(name1, ^{
    select * in conn1
}
dispatch_async(name2, ^{
    select * in conn2
}
dispatch_async(name3, ^{
    select * in conn3
}

2 个答案:

答案 0 :(得分:0)

这并不令人惊讶。所有线程都使用与数据库的共享连接,并在其上进行同步。结果,在给定时刻只有一个线程真正执行。添加上下文切换,您就会发现性能下降的原因。

如果你为每个线程提供自己的连接,你的线程中就没有同步,你应该看到性能提升。

答案 1 :(得分:0)

我试着回答一个例子。对于此场景的目的而言,客户端如何与服务器或上下文切换,虚拟化,多核等进行通信并不重要(但请注意,当您在规范中设计系统时会考虑所有这些因素):

您有一台拥有N个客户端的服务器。客户来来往往,并有不同的要求。一些客户提出快速,小型和频繁的请求。其他人提出的请求需要更长时间才能返回。

如果你有一个进程/线程,你一次只能处理一个客户端的一个请求 - 你有一堆客户端,每个客户端都有一堆请求。

现在,假设您要使用线程来并行化您的工作负载,您可以为每个客户端提供一个线程(多种可能之一)。你将拥有一堆线程(每个线程代表一个客户端)。然后每个线程都有一个该客户端请求的堆栈。操作系统将在这些多个任务之间分割(上下文切换)处理时间,您将获得一个完整的响应。

您当前的方法没有探索并行处理的使用 - 您只是要求线程执行相同的工作。

即便如此,仅凭这一点并不足以让您的代码线性增加时间。我怀疑在某个地方,你可能正在共享相同的资源 - 这将成为瓶颈。

你可以谷歌搜索什么时候使用线程的材料。我发现了解线程的最佳资源之一是C10k problem。您可以找到论文here的存档版本。