关于线程同步与双队列性能
2009年7月12日星期日
1问题背景
这是在2008年3月学习多线程编程时遇到的一个问题。当时我写了一个代码片段,其中两个线程共享一个队列,一个线程往队列中写数据,而另一个线程从队列中读取数据。这是典型的生产者和消费者模型。但在这里并不适合使用semaphore来做。
由于当时的我对多线程编程不太熟练,在线程中大量使用了printf输出调试信息,printf是典型的IO操作会引起线程的切换,所以打出来的信息也显示了线程切换十分频繁,几乎每一个数据入队列后,就立即被另一个线程抢占,并出队列,队列的长度一直为0或1,处理效率非常低。
在本周四,我有一个与架构师讨论问题的机会,我便找架构师请教了这个问题。当时我给架构师描述了我的问题,也许是我自己基础不好,架构师并不能很好的理解我的意思,但架构师根据我的描述给了我一些意见:
1、
2、
3、
4、
根据架构师的建议,我在公司里完成了这个程序,使用了两种方式:共享队列和双队列。
2第一种方式,共享队列
两个线程共享一个队列,一个往里写,一个往外读,我将写入数据的那个线程叫做writer,读出数据的那个线程叫做reader。这样,writer线程在工作时,reader线程只能等待,reader线程在工作时写线程只能等待。有人会说,可以多来几个reader这样可以使用RWLOCK,但根据应用场景,这里就只有一个消费者。这是一种最简单的方式,也是最基本的方式,效率也很低。在这里就不再讨论这个方式的实现了。
3第二种方式,双队列
两个线程各自一个队列,writer线程往队列1写数据,reader线程从队列2读数据,而在队列2为空时,我将队列1中的数据拼接或交换到队列2中,这样只有这个短暂的交换或拼接动作需要加锁。
那么这里还有个问题,当队列1中有多少数据后拼接到队列2的效率是最高的呢?架构师给了一个建议,先以16个、32个、64个这样的步进进行测试,直到找到性能最好的队列拼接长度。而我最后没有使用架构师给出的这个建议,而是模拟内核与用于空间之间的网络读写接口,这样就把这个任务给了系统调度,大概策略如下:
1、
2、
3、
a)
b)
c)
d)
根据测试双队列的性能后,发现比共享队列的性能高一个数量级(10倍),这些测试数据在公司里的Intel P4 HT 3.0G 1.5GMEM上测试的出来的,而本文实在家里写的,所以数据没有在这里给出。