分享
 
 
 

Java 集合与队列的插入、删除在并发下的性能比较

王朝学院·作者佚名  2016-05-05
窄屏简体版  字體: |||超大  

这两天在写一个java多线程的爬虫,以广度优先爬取网页,设置两个缓存:

•一个保存已经访问过的URL:vistedUrls

•一个保存没有访问过的URL:unVistedUrls

需要爬取的数据量不大,对URL压缩后,可以把这两个数据结构都放入内存,vistedUrls很显然用HashSet<String>实现,因为已经访问的URL只会添加,不会删除和修改,使用HashSet可以高效判断一个URL是否已经访问。

纠结unVistedUrls该用什么数据结构,如果用队列的话,并发情况下,队列中可能会用重复的URL,比如一个线程A爬了CSDN的一个URL1,另一个线程B爬了博客园的一个URL2,URL1和URL2的页面都有一个相同的出链URL3,线程A把URL3加入到unVistedUrls的队尾,等待下次爬取,但在URL3被爬取之前,线程B也把URL3加到队尾,这样队列中就有两个相同的URL,可能会导致重复爬取网页,当然可以通过其他方法来保证不会重复爬取。

然后就想能否也用Set来保存未访问的URL,这样在添加新的URL时,自动去重处理了,能够有效保证不爬取重复网页。但是unVistedUrls会有大量的插入和删除操作,我认为对集合进行大量的插入删除性能会比较低,为了测试集合的插入删除性能对比队列低多少,我写了一个简单的并发测试:

复制代码

1 /**

2 * 测试集合与队列的插入与读写性能

3 *

4 * @author jiqunpeng@Gmail.com

5 *

6 */

7 public class SetQueueTest {

8 // 随即数构造器

9 PRivate static Random r = new Random(10);

10 // 控制测试线程停止的原子变量

11 private static AtomicBoolean stop = new AtomicBoolean(false);

12

13 /***

14 * 基类,供测试用

15 *

16 * @author jiqunpeng@gmail.com

17 *

18 */

19 static abstract class Service {

20 // 操作的计数器

21 protected long count = 0;

22

23 // 添加一堆元素,并去一个元素

24 public abstract String addAndPick(List<String> elements);

25

26 // 取一个元素

27 public abstract String pickOne();

28

29 /**

30 * 打印操作次数

31 */

32 public void tell() {

33 System.out.println(this + " :\t" + count);

34 }

35 }

36

37 /***

38 * 采用TreeSet的集合工具

39 *

40 * @author jiqunpeng@gmail.com

41 *

42 */

43 static class SetService extends Service {

44 private TreeSet<String> set = new TreeSet<String>();

45

46 @Override

47 public synchronized String addAndPick(List<String> elements) {

48 count++;

49 set.addAll(elements);

50 return set.pollFirst();

51 }

52

53 @Override

54 public synchronized String pickOne() {

55 count++;

56 return set.pollFirst();

57 }

58

59 }

60

61 /***

62 * 采用LinkedList的队列工具

63 *

64 * @author jiqunpeng@gmail.com

65 *

66 */

67 static class QueueService extends Service {

68 private Queue<String> queue = new LinkedList<String>();

69

70 @Override

71 public synchronized String addAndPick(List<String> elements) {

72 count++;

73 queue.addAll(elements);

74 return queue.poll();

75 }

76

77 @Override

78 public synchronized String pickOne() {

79 count++;

80 return queue.poll();

81 }

82 }

83

84 /***

85 * 测试类

86 *

87 * @author jiqunpeng@gmail.com

88 *

89 */

90 static class Tester implements Runnable {

91 // 绑定要测试的工具对象

92 private Service service;

93

94 Tester(Service s) {

95 this.service = s;

96 }

97

98 @Override

99 public void run() {

100 while (stop.get() == false) {

101 List<String> elements = new ArrayList<String>();

102 int len = r.nextInt(200) + 8;

103 for (int i = 0; i < len; i++) {

104 elements.add(String.valueOf(r.nextInt()));

105 }

106 service.addAndPick(elements);

107 for (int i = 0; i < 104; i++)

108 service.pickOne();

109 }

110 }

111 }

112

113 /***

114 * 多线程方式,测试一个插入、删除工具

115 *

116 * @param service

117 * @param time

118 * @param unit

119 * @throws InterruptedException

120 */

121 private static void test(Service service, int time, TimeUnit unit)

122 throws InterruptedException {

123 ExecutorService execs = Executors.newCachedThreadPool();

124 for (int i = 0; i < 20; i++) {

125 execs.execute(new Tester(service));

126 }

127 execs.shutdown();

128 unit.sleep(time);

129 stop.compareAndSet(false, true);

130 service.tell();

131 }

132

133 public static void main(String[] args) throws InterruptedException {

134 Service setService = new SetService();

135 test(setService, 5, TimeUnit.SECONDS);

136 stop.compareAndSet(true, false);// 重置终止条件

137 Service queueService = new QueueService();

138 test(queueService, 5, TimeUnit.SECONDS);

139 }

140 }

复制代码

输出的结果如下:

SetQueueTest$SetService@5e9de959 : 7149859

SetQueueTest$QueueService@11b343e0 : 24303408

测试结果让我感到吃惊,TreeSet的插入删除效率确实比LinkedList低,20个线程跑了10秒,使用队列,插入删除24303408次,使用集合,插入删除7149859次。它们之间差距并不大,队列只比集合快2~3倍。属于同一个数量级。于是我这个小型的爬虫应该放心的选择用Set作为unVistedUrls的实现。

转载请注明出处:www.cnblogs.com/fengfenggirl

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有