就是说,当多个线程访问临近的地址空间的时候,比如struct { int a; int b; } object;线程1读域object.a,线程2写object.b这时可能会出现一个伪共享现象,因为object的域a和b很可能在一个Cache行上(Cache行是CPU缓存换入换出的最小单位),这个时候,核A上正在运行线程1,核B上正在运行线程2,而核B改动object.b的时候,CPU缓存协议机制就会把这个改动交给核A(因为核A正在关注这个Cache行),而这种关注是无效的,因为核A根本不关心object.a。这样一来,无论是核A对object的a域进行改动,还是核B对object的b域进行改动都会导致无效的CPU Cache协议行为,这就是伪共享现象,频繁的此类现象称为“Cache行乒乓”,这段Cache行就像乒乓球一样在两个核之间被推来推去。
网络上处理的是字节流
自然不存在对齐的问题如果new一块内存然后分割成结构体结构体内部是会对齐的
你说的地址不整齐是什么意思?
实际会有多少? 我在读写流的时候不用结构体的, 而是直接用变量的, 结构体只会用在链表里面, 而且没有强制用1BYTE对齐, 都是由编译器默认对齐值的.
唯一较为担心的是内存分配, 整个服务器的代码, 所有要用堆的地方, 都是用内存池来做的, 虽然结构体是按CPU位数对齐的, 但内存划分的时候, 虽然多少给多少而已, 这样在一块连续的内存块上分成了很多个结构体, 这样会不会导致结构体即使对齐了也读取缓慢?
但处理这些数据的时候,不对齐会导致CPU的浪费如何处理这两者之间的矛盾,楼下解答
这里会有我想要的答案了. 我想问的问题应该解决了. 也给一下我的见解:
1. 只有在结构对齐, 并且首地址对齐的情况下, CPU才可以实现最快的存取速度. 任何一方不满足, 都会降低效率.2. 序列散列, 网络操作都只能够是按BYTE进行, 那么不采用结构体而直接用单一的变量来读取会是最快的.3. 内存池的使用, 只有在内存池内部所有结构体均为CPU默认对齐的方式, 并且在向其申请内存块时, 申请大小不满足 大小 % CPU默认对齐值 == 0 时, 进行补充相应的大小, 以实现所有的内存块首地址均为对齐值的倍数, 这样才能够实现最快的读写效率.谢谢各位协助
为什么这些符号都能打出来···我自己做的WEB项目就不行啊
这跟你将你的C结构体放在内存哪里没什么关系,关键看你的结构体上域的存取,比如类似C代码: p->age=3 这类操作,看age的地址是不是自然对齐,如果是自然对齐,性能就没有损失。
字节对齐是仅对内存而言的,因为仅对CPU体系结构对内存的访问而言。
结构体是有关系的, new, malloc, HeadAlloc 这些操作, 分配的内存块首地址均是自然对齐的地址, 即:
new BYTE[123] 还是 new StructA 或者 new ClassA, 所有这些Instance, 首地址均为自然对齐. 但假如StructA里面有BYTE, 或WORD, 或BYTE[123], 然后加上Push(1)的话, 就会导致结构体成员访问时, 存在非自然对齐的地址. 就算不是用new, 而是在栈空间里面也好, 只要结构是非自然对齐的, 那么即使首地址已经帮你对齐好, 成员访问的时候依旧会导致地址不对齐. 使用内存池来分配所有堆空间时, 申请的内存池, 首地址是自然对齐的, 但假如分割的时候不按自然对齐的方式, 那么即使结构体是自然对齐, 也依旧会导致二次访问取值的问题. 那个讨论过的贴子里面说得很清楚了. 只要访问的地址不是自然对齐, 就会导致二次访问取值.今天晚上我把服务器除了数据流那里只能够按BYTE操作以外, 其他地方都搞成对齐了, 总体的速度的确有点提升, 但只有3% ~ 4%左右的提升, 或者是因为我不喜欢用结构体来序列散列, 所以也就这么一点了..距离10万/s 并发, 目前在我的i5上还差20%, 可能换上i7能够上了.
判断Client和Server字节顺序当然可以节省Server的顺序变换, 但直接用struct来写报文当然是可行的, 但却要客户端在接收的时候做很多判断的. 交互之前获了服务器字序和位数, 然后定义相应的struct和读取方式. 不过可惜的是, 让网络在每个数据包里面传送多几个B(为对齐的B)会导致更大的性能损失的. 几个B的预留空间对于本机的CPU和内存操作来说, 根本算不上时间和浪费, 但对于网络传送来说, 每个包都有几B浪费的时候, 这就问题大了. 所以, 现世的服务器, 用上struct写报文的, 都会是以BYTE对齐, 至于字节顺序来说, 既然都是按BYTE复制的话, 反过来复制来按顺序复制, 速度也是千万级别下都没有时间区别的, 所以不太推荐你说的方式.
就是说,当多个线程访问临近的地址空间的时候,比如struct {
int a;
int b;
} object;线程1读域object.a,线程2写object.b这时可能会出现一个伪共享现象,因为object的域a和b很可能在一个Cache行上(Cache行是CPU缓存换入换出的最小单位),这个时候,核A上正在运行线程1,核B上正在运行线程2,而核B改动object.b的时候,CPU缓存协议机制就会把这个改动交给核A(因为核A正在关注这个Cache行),而这种关注是无效的,因为核A根本不关心object.a。这样一来,无论是核A对object的a域进行改动,还是核B对object的b域进行改动都会导致无效的CPU Cache协议行为,这就是伪共享现象,频繁的此类现象称为“Cache行乒乓”,这段Cache行就像乒乓球一样在两个核之间被推来推去。
学习了, 原来还有这种限制. struct会这样的话, 那么class也会发生这样的情况了. 也就是说必须把类里面异步访问的数据必须把间隔划分开来存放对吧. 有几个异步操作的类为了代码清晰的确是拼在一起写了.谢谢指教. 结贴.
对,就是说:各个线程的本地数据的地址之间要保持足够的间隔,以将他们隔离在不同的Cache行上(Cache行的大小跟CPU类型相关)。
这点不太可能吧...汇编写得好与坏是能够直接影响的. 即使编译器有很大程度的优化, 但其实还是没有充分利用好CPU的寄存器的. 利用好寄存器, 运行速度可以接近CPU的频率, 但直接编译器编译出来的, 其实跟CPU的频率速度差很远的.
等 级: #81楼 得分:0回复于:2011-10-14 22:53:15
引用 79 楼 luojian2003 的回复:性能问题要看你代码的运行情况,一般情况下不会成瓶颈的不是瓶颈的问题, 而是进行最大优化的问题
有很多人, 或者说是我见过的项目里面吧, 特别是delphi, 写网络数据流的时候经常采用
XXXX = package struct
a: BYTE
b: Interer
...
end;然后外部直接操作这个struct, 像SOCKADDR那样, 要变换字节顺序的就先变换字节顺序, 最后就是直接把整个struct按字节复制进数据流.
然后在对方收到足够大小的数年流时, 直接把struct作为buffer, 从recv里面直接接收回来, 然后把整个数据变成struct, 然后操作struct. 这时候这个struct字节不对齐, 而外部就是经常通过这个struct来访问其内部成员的时候, 就降低速度了.这样写, 其实的确是带来很多方便和代码维护也较为容易的, 起码比起一个一个变量来写好看多了, 一种协议就是定义一个结构体. 只是我本人不喜欢这样写而已, 其实这样写的确代码是比较容易维护的. 我自己的协议都是没有定义任何结构体的, 都是直接按分析, 写注释, 直接写数据的. 所以不存在经常访问不对齐的struct的问题
网络上传输的结构体,是否字节对齐和你如何序列化有关,为了尽量减少传输的字节,应该是连续存放的。
字节对齐是针对内存管理的,和网络传输没有无关。
数据在网络中按什么方式传输完全可以由序列和散列的方式来决定。