`
dongliwei122
  • 浏览: 79462 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

这个循环太让人郁闷了

阅读更多
今天做了一个关于Webservice的测试,测试的目的是向服务器获取1W条用户信息(XML格式),本来打算做1W、5W、10W条的测试,但是在1W条的时候就卡住了。生成数据竟然用了将近半个小时,郁闷!大家帮看一下啊!
不过也好,也暴露了一些问题,比如:Webservice超时、海量数据(XML)的解析
package cn.com.javaeye;

import java.util.Date;

/**
 * <br>
 *文件名:Test.java<br>
 *@author dongliwei<br>
 *版本:<br>
 *描述:<br>
 *创建时间:Apr 2, 2009 6:16:34 PM<br>
 *文件描述:<br>
 *修改者:<br>
 *修改日期:<br>
 *修改描述:<br>
 */
public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		long begin = new Date().getTime();
		String xml = getXML(1);
		long end = new Date().getTime();
		System.out.println("生成数据共耗时:" + (end-begin) + "毫秒");
	}

	/**
	 * 获取用户
	 * @param count 单位:万
	 * @return
	 */
	public  static String getXML(int count){
		count = count*10000;
		String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
			   +"<users>";
		for(int  i = 0 ; i < count;i++){
			xml += 	"<user>"
						+"<id>001</id>"
						+"<name>zhangsan</name>"
						+"<empno>086001</empno>"
						+"<password>123456</password>"
						+"<mail>zhangsan@sina.com</mail>"
						+"<mobile>13733027580</mobile>"
						+"<address>北京市海淀区</address>"
						+"<sex>男</sex>"
						+"<organise>012</organise>"
						+"<role>1,2,3</role>"
						+"<group>1,5</group>"
					+"</user>";
			//System.out.println("生成" + (i+1) + "条数据");
		}
		xml += "</users>";
		return xml;
	}
}

经metadmin的指点,使用StringBuffer,就是不一样啊,仅仅用了239毫秒,在此谢过了!下面是修改过的代码
package cn.com.javaeye;

import java.util.Date;

/**
 * <br>
 *文件名:Test.java<br>
 *@author dongliwei<br>
 *版本:<br>
 *描述:<br>
 *创建时间:Apr 2, 2009 6:16:34 PM<br>
 *文件描述:<br>
 *修改者:<br>
 *修改日期:<br>
 *修改描述:<br>
 */
public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		long begin = new Date().getTime();
		String xml = getXML(1);
		long end = new Date().getTime();
		System.out.println("生成数据共耗时:" + (end-begin) + "毫秒");
	}

	/**
	 * 获取用户
	 * @param count 单位:万
	 * @return
	 */
	public  static String getXML(int count){
		count = count*10000;
		StringBuffer xml = new StringBuffer();
		
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		xml.append("<users>");
		for(int  i = 0 ; i < count;i++){
			xml.append("<user>");
			xml.append("<id>001</id>");
			xml.append("<name>zhangsan</name>");
			xml.append("<empno>086001</empno>");
			xml.append("<password>123456</password>");
			xml.append("<mail>zhangsan@sina.com</mail>");
			xml.append("<mobile>13733027580</mobile>");
			xml.append("<address>北京市海淀区</address>");
			xml.append("<sex>男</sex>");
			xml.append("<organise>012</organise>");
			xml.append("<role>1,2,3</role>");
			xml.append("<group>1,5</group>");
			xml.append("</user>");
			System.out.println("生成" + (i+1) + "条数据");
		}
		xml.append("</users>");
		return xml.toString();
	}
}
分享到:
评论
35 楼 hillshills 2009-06-25  

  当然StringBuffer或StringBuilder是首选哦。

  LZ貌似还是初学......
34 楼 RednaxelaFX 2009-04-25  
抛出异常的爱 写道
那是在jvm可感知的范围内.....

jvm又不是先知....知道你隔80行后还要去加个字符串

JVM确实是不知道。把+换成StringBuilder.append是编译器做的而不是JVM做的。像这个:
public class Foo {
    public static void main(String[] args) {
        String a = "";
        String b = "";
        String c = "";
        String d = "";
        String e = a + b + c;
        e = e + d;
    }
}

编译出来的.class文件就跟这个基本等价:
public class Foo {
    public static void main(String[] args) {
        String a = "";
        String b = "";
        String c = "";
        String d = "";
        String e = new StringBuilder()
                   .append(a)
                   .append(b)
                   .append(c)
                   .append(d)
                   .toString();
    }
}

唯一不等价的地方就是.class文件里main方法的LineNumberTable的数据不一样了。
33 楼 抛出异常的爱 2009-04-25  
qianjigui 写道
sunnycare 写道
晕。
貌似以前做过测试,看了字节码,发现java会自动将string+string优化成stringbuilder的append。

说实话,我也是受这种教育的。
不过经过测试确实如楼主说所,存在巨大差距。我直接将那个倒霉的string+string给当了。
我在编译时没有加参数。
很多人说 写道

Java的编译器在遇到比较长的字符串+操作,内部会自动变成StringBuilder的append操作

那是在jvm可感知的范围内.....

jvm又不是先知....知道你隔80行后还要去加个字符串
32 楼 qianjigui 2009-04-25  
sunnycare 写道
晕。
貌似以前做过测试,看了字节码,发现java会自动将string+string优化成stringbuilder的append。

说实话,我也是受这种教育的。
不过经过测试确实如楼主说所,存在巨大差距。我直接将那个倒霉的string+string给当了。
我在编译时没有加参数。
很多人说 写道

Java的编译器在遇到比较长的字符串+操作,内部会自动变成StringBuilder的append操作
31 楼 sunnycare 2009-04-08  
晕。
貌似以前做过测试,看了字节码,发现java会自动将string+string优化成stringbuilder的append。
30 楼 jeasony 2009-04-08  
呵呵。碰到大数据,才发现。String和StringBuffer有如此大的性能差距。。
29 楼 量产型人型自走炮 2009-04-03  
kimmking 写道

StringBuilder的是 (oldCapacity+1)*2 一直是偶数

总之要+1 这个+1在哪里只是具体设计的问题吧=_=
kimmking 写道

HashMap是 oldCapacity*2 一直是2的幂

其实我更关心的是他的再散列寻址....
28 楼 jltest 2009-04-03  
。。。。。每次都被lz的帖子给骗进来
27 楼 kimmking 2009-04-03  
<p>再来看看HashMap的容量扩张,因为hash要考虑寻址的效率,所以有了装填因子的概念,不能被填的太满,默认是0.75(.net的hashtable我记得好像是0.72)。</p>
<p>怎么也不会装满的~</p>
<p>初始的实际容量至少是1----initialCapacity参数为0的时候,下面这个没用:</p>
<p> </p>
<pre name="code" class="java">// Find a power of 2 &gt;= initialCapacity
        int capacity = 1;
        while (capacity &lt; initialCapacity)
            capacity &lt;&lt;= 1;</pre>
<p> 不过幸运的是,每次put或是putAll的addEntry的时候,都会判断下,不够就*2~~, 为了计算hash方便,一直取2的幂:</p>
<p> </p>
<pre name="code" class="java">void addEntry(int hash, K key, V value, int bucketIndex) {
Entry&lt;K,V&gt; e = table[bucketIndex];
        table[bucketIndex] = new Entry&lt;K,V&gt;(hash, key, value, e);
        if (size++ &gt;= threshold)
            resize(2 * table.length);
    }</pre>
<p> </p>
<p>----------------------------------------</p>
<p>默认的初始容量问题: StringBuilder是16,ArrayList是10,HashMap是16</p>
<p> </p>
<p>默认的容量增长:StringBuilder的是 (oldCapacity+1)*2 一直是偶数</p>
<p>  ArrayList是 (oldCapacity * 3)/2 + 1 </p>
<p>HashMap是 oldCapacity*2 一直是2的幂</p>
<p> </p>
<p>.net的hashtable是取oldCapacity*2 最接近的一个素数作为容量~~</p>
<p> </p>
26 楼 kimmking 2009-04-03  
<p>在看看ArrayList的扩容,newCapacity = oldCapacity *3/2+1; 大概是1.5倍,这个确保新容量至少是1。</p>
<p>不过考虑到AbstractStringBuilder一般都是直接加一批char,</p>
<p>List一般加一个(addAll特殊考虑下,用minCapacity和newCapacity )。</p>
<p>貌似new ArrayList(0),然后加入一个长度大于1的集合,这时List被充满了。~~</p>
<p> </p>
<p>------------------------------------------------------------------------------------------</p>
<p> </p>
<pre name="code" class="java">    public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity &gt; oldCapacity) {
     Object oldData[] = elementData;
     int newCapacity = (oldCapacity * 3)/2 + 1;
         if (newCapacity &lt; minCapacity)
  newCapacity = minCapacity;
     elementData = (E[])new Object[newCapacity];
     System.arraycopy(oldData, 0, elementData, 0, size);
}
    }



public boolean addAll(Collection&lt;? extends E&gt; c) {
Object[] a = c.toArray();
        int numNew = a.length;
ensureCapacity(size + numNew);  // Increments modCount 
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
return numNew != 0;
    }
</pre>
<p> </p>
25 楼 neptune 2009-04-03  
用StringBuilder还可以快十几秒
24 楼 超级潜水员 2009-04-03  
有够晕,这么大量根本就不应该放在内存中。

应该直接传一个Writer进行,然后在Writer写入。
23 楼 kimmking 2009-04-03  
量产型人型自走炮 写道
RednaxelaFX 写道
night_stalker 写道
弱问加 1 的意义何在……

印象中在哪里看到过这个设计理由的……嗯我想不起来了。但Sun的JDK里就是这么实现的 =v=


这个..其实是为了对付初始容量为0的情况=v=

+1,觉得是如果count == value.length的话,
加进来不至于value满了~~
22 楼 kimmking 2009-04-03  
量产型人型自走炮 写道
RednaxelaFX 写道
night_stalker 写道
弱问加 1 的意义何在……

印象中在哪里看到过这个设计理由的……嗯我想不起来了。但Sun的JDK里就是这么实现的 =v=


这个..其实是为了对付初始容量为0的情况=v=

// 初始容量==0这里也不需要+1,



public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
        int len = str.length();
if (len == 0) return this;
int newCount = count + len;  // count 不小于0,len至少是1
if (newCount > value.length) // 初始是0的话,这里也>=1
    expandCapacity(newCount); // 下面
str.getChars(0, len, value, count);
count = newCount;
return this;
    }

void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2; // 如果不+1就可能是0
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {          
            newCapacity = minimumCapacity;  // 这里也至少是1
}
char newValue[] = new char[newCapacity];
System.arraycopy(value, 0, newValue, 0, count);
value = newValue;
    }

21 楼 量产型人型自走炮 2009-04-03  
RednaxelaFX 写道
night_stalker 写道
弱问加 1 的意义何在……

印象中在哪里看到过这个设计理由的……嗯我想不起来了。但Sun的JDK里就是这么实现的 =v=


这个..其实是为了对付初始容量为0的情况=v=
20 楼 rrrrutdk 2009-04-03  
StringBuffer用于多线程,单线程使用StringBuilder会更快。
19 楼 iaimstar 2009-04-03  
1 好好看看java基础,否则会害死将来的人.
2 如果不要求线程同步,请用stringBuilder,比buffer快
3 代码很整齐,赞一下
4 万单位的数据,成功率太低,分包吧
18 楼 RednaxelaFX 2009-04-03  
night_stalker 写道
弱问加 1 的意义何在……

印象中在哪里看到过这个设计理由的……嗯我想不起来了。但Sun的JDK里就是这么实现的 =v=
17 楼 night_stalker 2009-04-03  
RednaxelaFX 写道

嗯,具体是(length + 1) * 2


弱问加 1 的意义何在……
16 楼 RednaxelaFX 2009-04-02  
night_stalker 写道
StringBuffer:
占用的空间大于字符串的长度,当字符串充满这块内存时,重新分配一块两倍大的内存给它。

嗯,具体是(length + 1) * 2

相关推荐

Global site tag (gtag.js) - Google Analytics