我正在向List
中添加数百万个自定义对象的条目。这被证明是非常慢的,而且图形用户界面也会随机冻结(在Windows上不响应),即使添加操作被包装在SwingWorker
中,所以它应该不会影响EDT。此外,CPU
利用率上升到70% - 90%左右。
我将列表初始化为:
List<SearchResult> updatedSearchResults = new ArrayList<>();
然后我不断地打电话给
SearchResult searchResult = new SearchResult(...);
updatedSearchResults.add(searchResult);
添加元素。
我知道ArrayList
内部使用了一个数组,该数组在满时会调整大小,并且所有元素都会被复制过来。但是,使用LinkedList
比使用ArrayList
要慢,而且不存在其他List实现。
根据this answer的说法,添加到ArrayList
具有O(1)
的性能。问题来了,为什么我收集所有结果的方法在性能方面仍然如此糟糕。SearchResult
是一个封装字段的简单数据对象,由于只设置字段,因此初始化它的成本很低。
相比之下,添加到列表中比通过网络套接字发送相同数量的数据要慢得多。这没有任何意义,因为本地操作应该总是比网络相关的操作快得多。
1 million
元素在大约0.2 seconds
时间内完成,但67 million
甚至不会在合理的时间内完成。它最多应该在几秒钟内完成。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
public class ListPerformanceTester
{
public enum ValueSize
{
EIGHT_BIT("8-Bit"),
SIXTEEN_BIT("16-Bit"),
THIRTY_TWO_BIT("32-Bit"),
SIXTY_FOUR_BIT("64-Bit"),
NINETY_SIX_BIT("96-Bit");
private String name;
ValueSize(String name)
{
this.name = name;
}
public int getBytesCount()
{
switch (this)
{
case EIGHT_BIT:
return 1;
case SIXTEEN_BIT:
return 2;
case THIRTY_TWO_BIT:
return 4;
case SIXTY_FOUR_BIT:
return 8;
case NINETY_SIX_BIT:
return 12;
}
throw new IllegalStateException("Bytes count undefined for " + this);
}
@Override
public String toString()
{
return name;
}
public static ValueSize parse(String name)
{
ValueSize[] valueSizes = values();
for (ValueSize valueSize : valueSizes)
{
String currentName = valueSize.toString();
if (currentName.equals(name))
{
return valueSize;
}
}
throw new IllegalArgumentException("No value size associated");
}
}
public static class SearchResult implements Cloneable, Comparable
{
private int address;
private ValueSize valueSize;
private BigInteger previousValue;
private BigInteger currentValue;
private BigInteger valueDifference;
public SearchResult(int address, BigInteger previousValue,
BigInteger currentValue, ValueSize valueSize)
{
this.address = address;
this.valueSize = valueSize;
this.previousValue = previousValue;
this.currentValue = currentValue;
setValueDifference();
}
private void setValueDifference()
{
BigInteger subtractionResult = previousValue.subtract(currentValue);
valueDifference = subtractionResult.abs();
}
private byte[] getBytes(BigInteger bigInteger) throws IOException
{
byte[] retrieved = bigInteger.toByteArray();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int bytesCount = getValueSize().getBytesCount();
int paddingBytes = bytesCount - retrieved.length;
if (paddingBytes >= 0)
{
byteArrayOutputStream.write(new byte[paddingBytes]);
byteArrayOutputStream.write(retrieved);
} else
{
writeWithoutLeadingNullBytes(byteArrayOutputStream, retrieved);
}
return byteArrayOutputStream.toByteArray();
}
private void writeWithoutLeadingNullBytes(ByteArrayOutputStream byteArrayOutputStream, byte[] bytes)
{
int index = 0;
boolean nonNullByteFound = false;
while (index < bytes.length)
{
byte value = bytes[index];
if (value != 0 || nonNullByteFound)
{
nonNullByteFound = true;
byteArrayOutputStream.write(value);
}
index++;
}
}
public int getAddress()
{
return address;
}
@Override
public boolean equals(Object object)
{
if (!(object instanceof SearchResult))
{
return false;
}
SearchResult searchResult = (SearchResult) object;
return searchResult.getAddress() == getAddress();
}
@Override
public int hashCode()
{
return Integer.hashCode(address);
}
public ValueSize getValueSize()
{
return valueSize;
}
@Override
public SearchResult clone()
{
return new SearchResult(address, previousValue, currentValue, valueSize);
}
@Override
public int compareTo(Object object)
{
return new Integer(address).compareTo(((SearchResult) object).getAddress());
}
}
public static void main(String[] arguments)
{
long milliseconds = System.currentTimeMillis();
int elementsCount = 2000000;
/*List<Integer> list = new ArrayList<>();
for (int elementIndex = 0; elementIndex < elementsCount; elementIndex++)
{
list.add(0);
}*/
List<SearchResult> searchResults = new ArrayList<>();
for (int elementIndex = 0; elementIndex < elementsCount; elementIndex++)
{
SearchResult searchResult = new SearchResult(0x12345678, new BigInteger("3"), new BigInteger("1"), ValueSize.EIGHT_BIT);
searchResults.add(searchResult);
}
System.out.println((System.currentTimeMillis() - milliseconds) / (double) 1000 + " seconds");
}
}
这里最大的问题是什么?
https://stackoverflow.com/questions/41411365
复制相似问题