| 蓝色键盘 回复于:2003-08-03 00:27:54
|
怀疑是不是只用两个队列比较费时间,因为每次不管读还是写都要加锁。
你的读写应该是你图上的send和read吧,如果是的话,你现在同步是怎么控制的。
|
| unicorns 回复于:2003-08-03 00:35:19
|
readthread 通过tcp拿到客户发来的东西会把他分解成
一个一个的请求,然后放进队列里,放的时候加锁
每个querythread轮询和readthread之间的队列,发现有东西就拿出来
进行查询操作。操作完后生成要发送的包,放到与 sendthread之间的队列中。
sendthread只管从队列中取包并发送。
连接描述字是随着其他信息一路传过来给sendthread的。
我说的读和写是指对队列的读写操作。
|
| 蓝色键盘 回复于:2003-08-03 00:40:22
|
对方支持异步吗?
|
| unicorns 回复于:2003-08-03 00:51:40
|
是的,确切的说那头也要我来写
呵呵。
|
| 大菠萝 回复于:2003-08-03 08:48:40
|
[quote:f84db3faa3]
现在是将数据库的表全部读入到内存中的三张HASH表里,所以查询线程应该花不了多长时间。
[/quote:f84db3faa3]
你用的是什么数据库?
我觉得你这样做,可能没有必要,可以在数据库中直接将数据表放入内存中,用位图索引,速度很快的,且这样做了,数据库能控制并发访问的,你可以试验一下,看能不能达到你的要求.在oracle中,将表放入内存是
alter table table_name storage(buffer_pool keep) ,其他的不知道了
自己控制的话,要将锁控制细一些,也就是要支持行锁定.不能一锁,就锁一个表,且能多个用户读一个行,但是这个时候不能有写的;一次只能有一个写,就是读写锁的功能.
比较复杂..........
还是试验一下数据库的方法,在说, 
|
| mengwg 回复于:2003-08-03 09:22:58
|
1、几个线程之间的时间差尽量减少。就是读到任务后处理线程能尽快处理,处理完后能尽快发送。
2、socket的缓冲区开大一些,避免发送不成功。
3、我想锁占用时间应该不会有多大影响。
4、每秒500个业务,采用这种C/S结构,非常难达到。如果用单个客户端测试,可能永远达不到,我想应理解成服务端并发处理能力,那么测试时需要启动多个客户端。可能更能测试出服务端的效率。
|
| unicorns 回复于:2003-08-03 11:08:56
|
[quote:560808c89e="大菠萝"]
你用的是什么数据库?
我觉得你这样做,可能没有必要,可以在数据库中直接将数据表放入内存中,用位图索引,速度很快的,且这样做了,数据库能控制并发访问的,你可以试验一下,看能不能达到你的要求.在oracle中,将表放?.........[/quote:560808c89e]
[quote:560808c89e="unicorns"]现在是将数据库的表全部读入到内存中的三张HASH表里,所以查询线程应该花不了多长时间。 [/quote:560808c89e]
不过你说的那个alter table是什么意思。很有兴趣听一下。
我加锁是给交换数据的队列加锁,是用双向链表实现的队列,这样要读写一个记录肯定要影响其他记录,只对一条记录加锁不好实现。
|
| unicorns 回复于:2003-08-03 11:20:39
|
[quote:8240c146f5="mengwg"]1、几个线程之间的时间差尽量减少。就是读到任务后处理线程能尽快处理,处理完后能尽快发送。
2、socket的缓冲区开大一些,避免发送不成功。
3、我想锁占用时间应该不会有多大影响。
4、每秒500个业务,..........[/quote:8240c146f5]
多谢多谢,看来mengwg是很有经验的
1。我现在是这么做的。在每个向队列放数据的动作中
是用一个阻塞的Queue.Lock()
[code:1:8240c146f5]
Queue.Lock() ;
Queue.AddTail(&data) ;
Queue.Unlock() ;
[/code:1:8240c146f5]
从队列中取数据是
[code:1:8240c146f5]
while(1){
Queue.Lock() ;
if (Queue.IsEmpty()){
Queue.Unlock() ;
usleep(1) ;
continue ;
}
pData = Queue.RemoveHead() ;
Queue.Unlock() ;
...............
...............
}
[/code:1:8240c146f5]
这样写能不能保证在第一时间处理,怎么能改进一下。
2。TCP的缓冲区默认是多大,最大有限制吗?我用的是SOLARIS 8
3。这是个定心丸,如果用多个队列交换的话,还有很多麻烦事要做。
4。现在是用线程池来支持并发的,不过测试条件还不具备,sigh。
|
| mengwg 回复于:2003-08-03 11:48:56
|
1、关于队列的同步我觉得方法不是很好。
while(1){
Queue.Lock() ;
if (Queue.IsEmpty()){
Queue.Unlock() ;
usleep(1) ;
continue ;
}
pData = Queue.RemoveHead() ;
Queue.Unlock() ;
...............
...............
}
如果系统对usleep支持得不好,可能延时较大(不同平台差别较大)。如果处理得好,那么占用系统资源非常多!lock、unlock属于内核操作。
具体的是否可以试试阻塞式读取。
2、TCP设置个1M、2M应该是可以得,你可查一下相关资料。
3、lock虽然不慢,但频繁调用吃CPU很厉害的。
4、我觉得需要综合考虑,不要为了你这一部分得效率占用太多资源,毕竟主机还要处理很多业务上的东西。片面的强调传输和对列的效率不大可取。
所以你在测试时应该注意观察主机CPU占用情况,注意不要多了,如1%以下是可以接受的。
|
| unicorns 回复于:2003-08-03 11:54:36
|
[quote:60199bdf86="mengwg"]1、关于队列的同步我觉得方法不是很好。
while(1){
Queue.Lock() ;
if (Queue.IsEmpty()){
Queue.Unlock() ;
usleep(1) ;
continue ;
}
pData = Queue.Remo..........[/quote:60199bdf86]
你的意思是把usleep去掉
我也知道这个不准,误差比较大
但是如果去掉的话,取队列的几个线程都在轮询队列,会不会LOCK的太频繁了
你提到的阻塞式读取是针对队列来说的吗
|
| 夜未眠 回复于:2003-08-03 12:44:25
|
不能让客户端直接连数据库吗?为什么要在中间加一块? 赞成[color=red:b9e77887fe]大菠萝[/color:b9e77887fe]的
|
| 灰色轨迹 回复于:2003-08-03 13:15:29
|
[quote:8841965acf="大菠萝"]
你用的是什么数据库?
我觉得你这样做,可能没有必要,可以在数据库中直接将数据表放入内存中,用位图索引,速度很快的,且这样做了,数据库能控制并发访问的,你可以试验一下,看能不能达到你的要求.在oracle中,将表放?.........[/quote:8841965acf]
查询线程的效率是否是最高的,建议你比较一下HASH表和直接访问数据库这两种方式
|
| 夜未眠 回复于:2003-08-03 14:33:47
|
对数据库没作任何优化的话当然是你人为的hash要高得多。
不过数据库有索引,并且有很多索引类型(postgresql就包括hash)。并且能够对经常触发的查询作出优化。如果建立索引并常对数据库作analyze,效率就完全是两回事了,我想这些数据库本身的功能你自己再写一个程式来完成是否有点儿多余?
|
| unicorns 回复于:2003-08-03 15:38:08
|
[quote:3f2b4f5847="夜未眠"]对数据库没作任何优化的话当然是你人为的hash要高得多。
不过数据库有索引,并且有很多索引类型(postgresql就包括hash)。并且能够对经常触发的查询作出优化。如果建立索引并常对数据库作analyze,效率就完全是两回事..........[/quote:3f2b4f5847]
具体需求具体分析嘛
做这个东西主要是在客户和数据库间建一个简单协议。
这样以后整个系统中的所有客户端都使用这个简单协议与这个程序通信
这样做的好处是以后如果数据库有所变动,只需要改这里而不需要去修改各个客户端。
至于查询速度,愚认为没有比我的HASH更快的了
因为我的HASH开了很大的内存,是不惜内存的换取速度(其实也没用多少)
机器有1g的内存,我最多用个200M了不起了。HASHKEY使用的是记录的ID,
散列就是简单求余,因为ID是连续的,所以基本没有冲突(当然闲置空间很多
但每个闲置空间也就是4个字节一个指针,加起来也没多少)。我查找起来就是一次求余操作就可以了。什么样的索引和优化可以比这样的HASH更快?
请大家关注于我提出的问题,其他方面由于具体需求的不同所产生的分歧就放在一边吧。谢谢
|
| snowpy 回复于:2003-08-03 15:56:04
|
1.每个客户端的连接数
2.是长连接还是短连接
3.是同步还是异步
[quote:d3216ad64e="unicorns"]大概是这样一个需求,通过TCP与CLIET建立一个连接
然后从CLIET读入请求,然后经过查询,最后将结果传回CLIET
我用pthread做的,目前的结构就是下面的图。
现在是将数据库的表全部读入到内存中的三张HASH表里,所?.........[/quote:d3216ad64e]
|
| deathbravo 回复于:2003-08-04 08:39:52
|
请问您的速度达到多少次了?
我的问题与您类似;
只是我没有自己hash
直接做数据库操作的
|
| gadfly 回复于:2003-08-04 10:30:31
|
不知道你这三类线程的比例如何安排的?
queue lock的怎么一个实现方式?
另外gcc有个-p参数,可以产生跟踪执行的数据。可以用prof工具分析。你可以试试看
|
| unicorns 回复于:2003-08-04 14:41:16
|
[quote:630b41be61="snowpy"]1.每个客户端的连接数
2.是长连接还是短连接
3.是同步还是异步
[/quote:630b41be61]
1,目前是单个客户端的测试,每个客户端一个连接
2,长连接
3,异步。
|
| unicorns 回复于:2003-08-04 14:42:45
|
[quote:cb7f51d9ab="deathbravo"]请问您的速度达到多少次了?
我的问题与您类似;
只是我没有自己hash
直接做数据库操作的[/quote:cb7f51d9ab]
发帖子的时候是每秒130到140的样子
现在把测试的客户端的程序改了一下,目前是每秒330的样子。
|
| unicorns 回复于:2003-08-04 14:48:12
|
[quote:1d4cf1bc97="gadfly"]不知道你这三类线程的比例如何安排的?
queue lock的怎么一个实现方式?
另外gcc有个-p参数,可以产生跟踪执行的数据。可以用prof工具分析。你可以试试看[/quote:1d4cf1bc97]
一个连接就只对应一个read和send
querythread的个数比例正在测试看如何才合适。
lock用的是pthread_mutex
pthread_mutex_lock()
不论读或写都要先把整个队列锁住,队列是用双链表实现的。
多谢大家关注,现在性能还算到了我可以接受的范围了,单个客户端一个连接每秒将近350个了。如果并发的话应该还会有所提高。谢谢大家
尤其感谢mengwg的意见。呵呵 //bow
|
| gadfly 回复于:2003-08-04 15:20:05
|
介绍一下调优的过程,让大家都学习一下经验吧。
|
| gadfly 回复于:2003-08-04 15:23:25
|
另外,我觉得是不是可以用条件变量来通知query thread。这种方式应该会比轮询方式要高效。
加精华了。很好的讨论话题。
|
| snowpy 回复于:2003-08-04 15:43:13
|
如果你的操作是纯内存而不含有数据库以及IO操作的话
每秒400条太慢了,起码应该上千条性能才算合格
[quote:ed7902c1f1="unicorns"]
一个连接就只对应一个read和send
querythread的个数比例正在测试看如何才合适。
lock用的是pthread_mutex
pthread_mutex_lock()
不论读或写都要先把整个队列锁住,队列是用双链表实现的。
多谢大?.........[/quote:ed7902c1f1]
|
| unicorns 回复于:2003-08-04 15:45:26
|
呵呵,gadfly斑竹
其实我这个过程比较简单,没多少能说的
主要是一开始就清楚哪里是性能的瓶颈
无非两个地方,一是网络通信,socket的收和发
二是线程间的通信队列
所以就抓住这两个地方反复试来试去。
调优感觉最困难的其实不是调而是找,发现瓶颈是比较困难的一件事情。
|
| unicorns 回复于:2003-08-04 15:47:47
|
[quote:8211c05070="snowpy"][/quote:8211c05070]
说的太对了
刚才我在试极限速度
单客户端一个连接,每秒约1400条,再超过就有点麻烦出现了。
|
| linuxsch 回复于:2003-08-05 18:17:29
|
你可以用少量线程来处理大量的连接,因为没来一个连结请求你就单独创建一个线程去处理的话,可能会降低效率,并且线程多了就会增加很多锁的机会,我在linux下就是用select 或是 poll 来处理这种问题的,感觉效果不错。你可以试试。
|