团队的编程比赛,题目是给一个文本文件,在去掉二十个常用词以后,统计出现频率前十位的词。

我采用的是哈希表,c++语言实现。

1.使用mmap,将内容映射到内存。

2.文本分割,处理边界条件,在ranges[]中指明每个区间的开始和结束位置。

3.Worker线程中分块处理,对于每一个单词,在哈希表中相应位置查找,插入。

4.Worker线程结束后,得到了有统计结果的哈希表,将结果进行过滤(去掉20个常用单词),装入vector中。

5.使用std::algorithm中的heap建堆,取出前十个元素。

优化

1.使用mmap而不是fread:fread会先将内容从磁盘拷贝到内存的内核空间,再转移到用户态,相比mmap来说,多了一次拷贝.

2.只采用了一张哈希表,避免多线程之间的合并,插入操作时没有加锁,而采用了类似于CAS的原子操作:

asm volatile(
“lock;\n\t”
“cmpxchgq %3, %2″
: “=a”(old)
: “0″(0), “m”(*p), “r”(np)
: “memory”);

关于cmpxchgq的介绍可以看这里。需要注意的是Intel格式汇编和Linux的AT&T格式不同。

3.最后过滤单词时,先判断长度,不符合的直接放过,可以减少比较次数。

总结

1.预处理(映射,分割)占用了比较长的时间,没有充分利用CPU,如果分块读入并处理,可能效果会更好。

2.最后简单建了一个巨大的heap来存放过滤后的结果,并建堆。这一步没有仔细考虑,应该还有更好的优化方案。

3.采用单链表处理冲突,该单链表只在尾部插入,没有删除操作,再加上CAS操作本身的原子性,可以保证insert操作的原子性,不过貌似这个操作还是有bug。

4.锁和系统调用都很消耗时间,在保证正确性的前提下,能不用尽量不用。