`
huobengluantiao8
  • 浏览: 1021976 次
文章分类
社区版块
存档分类
最新评论

调整 Java I/O 性能

 
阅读更多

这篇文章讨论和阐明了提供 JavaTM I/O 性能的多种技术。大多技术围绕调整磁盘文件 I/O,但是有些内容也同样适合网络 I/O 和窗口输出。第一部分技术讨论底层的I/O问题,然后讨论诸如压缩,格式化和串行化等高级I/O问题。然而这个讨论没有包含应用设计问题,例如搜索算法和数据结构,也没有讨论系统级的问题,例如文件高速缓冲。

当我们讨论Java I/O时,值得注意的是Java语言采取两种截然不同的磁盘文件结构。一个是基于字节流,另一个是字符序列。在Java语言中一个字符有两个字节表示,而不是像通常的语言如c语言那样是一个字节。因此,从一个文件读取字符时需要进行转换。这个不同在某些情况下是很重要的,就像下面的几个例子将要展示的那样。

低级 I/O I问题

加速I/O的基本规则
缓冲
读写文本文件
格式化的代价
随机访问
高级I/O问题

压缩
高速缓冲
分解
串行化
获取文件信息
更多信息
加速I/O的基本规则

作为这个讨论的开始,这里有几个如何加速I/O的基本规则:

避免访问磁盘
避免访问底层的操作系统
避免方法调用
避免个别的处理字节和字符
很明显这些规则不能在所有的问题上避免,因为如果能够的话就没有实际的I/O被执行。考虑下面的计算文件中的新行符('/n')的三部分范例。

方法1: 读方法
第一个方法简单的使用FileInputStream的read方法:

import java.io.*;

public class intro1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
int cnt = 0;
int b;
while ((b = fis.read()) != -1) {
if (b == '/n')
cnt++;
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

然而这个方法触发了大量的底层运行时系统调用--FileInputStream.read--返回文件的下一个字节的本机方法。
方法 2: 使用大缓冲区
第二种方法使用大缓冲区避免了上面的问题:

import java.io.*;

public class intro2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
BufferedInputStream bis =
new BufferedInputStream(fis);
int cnt = 0;
int b;
while ((b = bis.read()) != -1) {
if (b == '/n')
cnt++;
}
bis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

BufferedInputStream.read 从输入缓冲区获取下一个字节,仅仅只访问了一次底层系统。
方法 3: 直接缓冲
第三种方法避免使用 BufferedInputStream 而直接缓冲,因此排除了 read 方法的调用:

import java.io.*;

public class intro3 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
byte buf[] = new byte[2048];
int cnt = 0;
int n;
while ((n = fis.read(buf)) != -1) {
for (int i = 0; i < n; i++) {
if (buf[i] == '/n')
cnt++;
}
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

对于一个1 MB 的输入文件,以秒为单位的执行时间是:


intro1 6.9
intro2 0.9
intro3 0.4

或者说在最慢的方法和最快的方法间是17比1的不同。

这个巨大的加速并不能证明你应该总是使用第三种方法,即自己做缓冲。这可能是一个错误的倾向特别是在处理文件结束事件时没有仔细的实现。在可读性上它也没有其它方法好。但是记住时间花费在哪儿了以及在必要的时候如何矫正是很有用。

方法2 或许是对于大多应用的 "正确" 方法.

缓冲

方法 2 和 3 使用了缓冲技术, 大块文件被从磁盘读取,然后每次访问一个字节或字符。缓冲是一个基本而重要的加速I/O 的技术,而且有几个类支持缓冲(BufferedInputStream 用于字节, BufferedReader 用于字符)。

一个明显得问题是: 缓冲区越大I/O越快吗?典型的Java缓冲区长1024 或者 2048 字节,一个更大的缓冲区有可能加速 I/O但是只能占很小的比重,大约5 到10%。

方法4: 整个文件
缓冲的极端情况是事先决定整个文件的长度,然后读取整个文件:

import java.io.*;

public class readfile {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
int len = (int)(new File(args[0]).length());
FileInputStream fis =
new FileInputStream(args[0]);
byte buf[] = new byte[len];
fis.read(buf);
fis.close();
int cnt = 0;
for (int i = 0; i < len; i++) {
if (buf[i] == '/n')
cnt++;
}
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个方法很方便,在这里文件被当作一个字节数组。但是有一个明显得问题是有可能没有读取一个巨大的文件的足够的内存。
缓冲的另一个方面是向窗口终端的文本输出。缺省情况下, System.out ( 一个PrintStream) 是行缓冲的,这意味着在遇到一个新行符后输出缓冲区被提交。对于交互来说这是很重要的,在那种情况下你可能喜欢在实际的输出前显示一个输入提示。

方法 5: 关闭行缓冲
行缓冲可以被禁止,像下面的例子那样:

import java.io.*;

public class bufout {
public static void main(String args[]) {
FileOutputStream fdout =
new FileOutputStream(FileDescriptor.out);
BufferedOutputStream bos =
new BufferedOutputStream(fdout, 1024);
PrintStream ps =
new PrintStream(bos, false);

System.setOut(ps);

final int N = 100000;

for (int i = 1; i <= N; i++)
System.out.println(i);

ps.close();
}
}

这个程序输出整数1到100000缺省输出,比在缺省的行缓冲情况下快了三倍。

缓冲也是下面将要展示的例子的重要部分,在那里,缓冲区被用于加速文件随机访问。

读写文本文件

早些时候曾提到从文件里面读取字符的方法调用的消耗可能是重大的。这个问题在计算文本文件的行数的另一个例子中也可以找到。:

import java.io.*;

public class line1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
BufferedInputStream bis =
new BufferedInputStream(fis);
DataInputStream dis =
new DataInputStream(bis);
int cnt = 0;
while (dis.readLine() != null)
cnt++;
dis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个程序使用老的DataInputStream.readLine 方法,该方法是使用用读取每个字符的 read 方法实现的。一个新方法是:

import java.io.*;

public class line2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
int cnt = 0;
while (br.readLine() != null)
cnt++;
br.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个方法更快。例如在一个有200,000行的 6 MB文本文件上,第二个程序比第一个快大约20%。

但是即使第二个程序不是更快的,第一个程序依然有一个重要的问题要注意。第一个程序在JavaTM 2编译器下引起了不赞成警告,因为DataInputStream.readLine太陈旧了。它不能恰当的将字节转换为字符,因此在操作包含非ASCII字符的文本文件时可能是不合适的选择。(Java语言使用Unicode字符集而不是ASCII)

这就是早些时候提到的字节流和字符流之间的区别。像这样的一个程序:

import java.io.*;

public class conv1 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("out1");
PrintStream ps =
new PrintStream(fos);
ps.println("/uffff/u4321/u1234");
ps.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

向一个文件里面写,但是没有保存实际的Unicode字符输出。Reader/Writer I/O 类是基于字符的,被设计用来解决这个问题。OutputStreamWriter 应用于字节编码的字符。
一个使用PrintWriter写入Unicode字符的程序是这样的:

import java.io.*;

public class conv2 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("out2");
OutputStreamWriter osw =
new OutputStreamWriter(fos, "UTF8");
PrintWriter pw =
new PrintWriter(osw);
pw.println("/uffff/u4321/u1234");
pw.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个程序使用UTF8编码,具有ASCII文本是本身而其他字符是两个或三个字节的特性。

格式化的代价
实际上向文件写数据只是输出代价的一部分。另一个可观的代价是数据格式化。考虑一个三部分程序,它像下面这样输出一行:


The square of 5 is 25

方法 1
第一种方法简单的输出一个固定的字符串,了解固有的I/O开销:

public class format1 {
public static void main(String args[]) {
final int COUNT = 25000;

for (int i = 1; i <= COUNT; i++) {
String s = "The square of 5 is 25/n";
System.out.print(s);
}
}
}

方法2
第二种方法使用简单格式"+":

public class format2 {
public static void main(String args[]) {
int n = 5;

final int COUNT = 25000;


for (int i = 1; i <= COUNT; i++) {
String s = "The square of " + n + " is " +
n * n + "/n";
System.out.print(s);
}
}
}

方法 3
第三种方法使用java.text包中的 MessageFormat 类:

import java.text.*;

public class format3 {
public static void main(String args[]) {
MessageFormat fmt =
new MessageFormat("The square of {0} is {1}/n");
Object values[] = new Object[2];


int n = 5;


values[0] = new Integer(n);
values[1] = new Integer(n * n);

final int COUNT = 25000;


for (int i = 1; i <= COUNT; i++) {
String s = fmt.format(values);
System.out.print(s);
}
}
}

这些程序产生同样的输出。运行时间是:


format1 1.3
format2 1.8
format3 7.8

或者说最慢的和最快的大约是6比1。如果格式没有预编译第三种方法将更慢,使用静态的方法代替:

方法 4
MessageFormat.format(String, Object[])

import java.text.*;

public class format4 {
public static void main(String args[]) {
String fmt = "The square of {0} is {1}/n";
Object values[] = new Object[2];


int n = 5;


values[0] = new Integer(n);
values[1] = new Integer(n * n);

final int COUNT = 25000;


for (int i = 1; i <= COUNT; i++) {
String s =
MessageFormat.format(fmt, values);
System.out.print(s);
}
}
}

这比前一个例子多花费1/3的时间。

第三个方法比前两种方法慢很多的事实并不意味着你不应该使用它,而是你要意识到时间上的开销。

在国际化的情况下信息格式化是很重要的,关心这个问题的应用程序通常从一个绑定的资源中读取格式然后使用它。

随机访问

RandomAccessFile 是一个进行随机文件I/O(在字节层次上)的类。这个类提供一个seek方法,和 C/C++中的相似,移动文件指针到任意的位置,然后从那个位置字节可以被读取或写入。

seek方法访问底层的运行时系统因此往往是消耗巨大的。一个更好的代替是在RandomAccessFile上建立你自己的缓冲,并实现一个直接的字节read方法。read方法的参数是字节偏移量(>= 0)。这样的一个例子是:

import java.io.*;

public class ReadRandom {
private static final int DEFAULT_BUFSIZE = 4096;

private RandomAccessFile raf;
private byte inbuf[];
private long startpos = -1;
private long endpos = -1;
private int bufsize;

public ReadRandom(String name)
throws FileNotFoundException {
this(name, DEFAULT_BUFSIZE);
}

public ReadRandom(String name, int b)
throws FileNotFoundException {
raf = new RandomAccessFile(name, "r");
bufsize = b;
inbuf = new byte[bufsize];
}

public int read(long pos) {
if (pos < startpos || pos > endpos) {
long blockstart = (pos / bufsize) * bufsize;
int n;
try {
raf.seek(blockstart);
n = raf.read(inbuf);
}
catch (IOException e) {
return -1;
}
startpos = blockstart;
endpos = blockstart + n - 1;
if (pos < startpos || pos > endpos)
return -1;
}

return inbuf[(int)(pos - startpos)] & 0xffff;
}

public void close() throws IOException {
raf.close();
}

public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}

try {
ReadRandom rr = new ReadRandom(args[0]);
long pos = 0;
int c;
byte buf[] = new byte[1];
while ((c = rr.read(pos)) != -1) {
pos++;
buf[0] = (byte)c;
System.out.write(buf, 0, 1);
}
rr.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个程序简单的读取字节序列然后输出它们。

如果有访问位置,这个技术是很有用的,文件中的附近字节几乎在同时被读取。例如,如果你在一个排序的文件上实现二分法查找,这个方法可能很有用。如果你在一个巨大的文件上的任意点做随机访问的话就没有太大价值。

压缩

Java提供用于压缩和解压字节流的类,这些类包含在java.util.zip 包里面,这些类也作为 Jar 文件的服务基础 ( Jar 文件是带有附加文件列表的 Zip 文件)。

下面的程序接收一个输入文件并将之写入一个只有一项的压缩的 Zip 文件:

import java.io.*;
import java.util.zip.*;

public class compress {
public static void doit(
String filein,
String fileout
) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(filein);
fos = new FileOutputStream(fileout);
ZipOutputStream zos =
new ZipOutputStream(fos);
ZipEntry ze = new ZipEntry(filein);
zos.putNextEntry(ze);
final int BUFSIZ = 4096;
byte inbuf[] = new byte[BUFSIZ];
int n;
while ((n = fis.read(inbuf)) != -1)
zos.write(inbuf, 0, n);
fis.close();
fis = null;
zos.close();
fos = null;
}
catch (IOException e) {
System.err.println(e);
}
finally {
try {
if (fis != null)
fis.close();
if (fos != null)
fos.close();
}
catch (IOException e) {
}
}
}
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("missing filenames");
System.exit(1);
}
if (args[0].equals(args[1])) {
System.err.println("filenames are identical");
System.exit(1);
}
doit(args[0], args[1]);
}
}

下一个程序执行相反的过程,将一个假设只有一项的Zip文件作为输入然后将之解压到输出文件:


import java.io.*;
import java.util.zip.*;

public class uncompress {
public static void doit(
String filein,
String fileout
) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(filein);
fos = new FileOutputStream(fileout);
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ze = zis.getNextEntry();
final int BUFSIZ = 4096;
byte inbuf[] = new byte[BUFSIZ];
int n;
while ((n = zis.read(inbuf, 0, BUFSIZ)) != -1)
fos.write(inbuf, 0, n);
zis.close();
fis = null;
fos.close();
fos = null;
}
catch (IOException e) {
System.err.println(e);
}
finally {
try {
if (fis != null)
fis.close();
if (fos != null)
fos.close();
}
catch (IOException e) {
}
}
}
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("missing filenames");
System.exit(1);
}
if (args[0].equals(args[1])) {
System.err.println("filenames are identical");
System.exit(1);
}
doit(args[0], args[1]);
}
}

压缩是提高还是损害I/O性能很大程度依赖你的硬件配置,特别是和处理器和磁盘驱动器的速度相关。使用Zip技术的压缩通常意味着在数据大小上减少50%,但是代价是压缩和解压的时间。一个巨大(5到10 MB)的压缩文本文件,使用带有IDE硬盘驱动器的300-MHz Pentium PC从硬盘上读取可以比不压缩少用大约1/3的时间。

压缩的一个有用的范例是向非常慢的媒介例如软盘写数据。使用高速处理器(300 MHz Pentium)和低速软驱(PC上的普通软驱)的一个测试显示压缩一个巨大的文本文件然后在写入软盘比直接写入软盘快大约50% 。

高速缓存

关于硬件的高速缓存的详细讨论超出了本文的讨论范围。但是在有些情况下软件高速缓存能被用于加速I/O。考虑从一个文本文件里面以随机顺序读取一行的情况,这样做的一个方法是读取所有的行,然后把它们存入一个ArrayList (一个类似Vector的集合类):


import java.io.*;
import java.util.ArrayList;

public class LineCache {
private ArrayList list = new ArrayList();

public LineCache(String fn) throws IOException {
FileReader fr = new FileReader(fn);
BufferedReader br = new BufferedReader(fr);
String ln;
while ((ln = br.readLine()) != null)
list.add(ln);
br.close();
}

public String getLine(int n) {
if (n < 0)
throw new IllegalArgumentException();

return (n < list.size() ?
(String)list.get(n) : null);
}

public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
LineCache lc = new LineCache(args[0]);
int i = 0;
String ln;
while ((ln = lc.getLine(i++)) != null)
System.out.println(ln);
}
catch (IOException e) {
System.err.println(e);
}
}
}

getLine 方法被用来获取任意行。这个技术是很有用的,但是很明显对一个大文件使用了太多的内存,因此有局限性。一个代替的方法是简单的记住被请求的行最近的100行,其它的请求直接从磁盘读取。这个安排在局域性的访问时很有用,但是在真正的随机访问时没有太大作用。

分解

分解 是指将字节或字符序列分割为像单词这样的逻辑块的过程。Java 提供StreamTokenizer 类, 像下面这样操作:


import java.io.*;

public class token1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
StreamTokenizer st = new StreamTokenizer(br);
st.resetSyntax();
st.wordChars('a', 'z');
int tok;
while ((tok = st.nextToken()) !=
StreamTokenizer.TT_EOF) {
if (tok == StreamTokenizer.TT_WORD)
;// st.sval has token
}
br.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

这个例子分解小写单词 (字母a-z)。如果你自己实现同等地功能,它可能像这样:

import java.io.*;

public class token2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
int maxlen = 256;
int currlen = 0;
char wordbuf[] = new char[maxlen];
int c;
do {
c = br.read();
if (c >= 'a' && c <= 'z') {
if (currlen == maxlen) {
maxlen *= 1.5;
char xbuf[] =
new char[maxlen];
System.arraycopy(
wordbuf, 0,
xbuf, 0, currlen);
wordbuf = xbuf;
}
wordbuf[currlen++] = (char)c;
}
else if (currlen > 0) {
String s = new String(wordbuf,
0, currlen);
// do something with s
currlen = 0;
}
} while (c != -1);
br.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

第二个程序比前一个运行快大约 20%,代价是写一些微妙的底层代码。
StreamTokenizer 是一种混合类,它从字符流(例如 BufferedReader)读取, 但是同时以字节的形式操作,将所有的字符当作双字节(大于 0xff) ,即使它们是字母字符。

串行化

串行化 以标准格式将任意的Java数据结构转换为字节流。例如,下面的程序输出随机整数数组:


import java.io.*;
import java.util.*;

public class serial1 {
public static void main(String args[]) {
ArrayList al = new ArrayList();
Random rn = new Random();
final int N = 100000;

for (int i = 1; i <= N; i++)
al.add(new Integer(rn.nextInt()));

try {
FileOutputStream fos =
new FileOutputStream("test.ser");
BufferedOutputStream bos =
new BufferedOutputStream(fos);
ObjectOutputStream oos =
new ObjectOutputStream(bos);
oos.writeObject(al);
oos.close();
}
catch (Throwable e) {
System.err.println(e);
}
}
}

而下面的程序读回数组:

import java.io.*;
import java.util.*;

public class serial2 {
public static void main(String args[]) {
ArrayList al = null;

try {
FileInputStream fis =
new FileInputStream("test.ser");
BufferedInputStream bis =
new BufferedInputStream(fis);
ObjectInputStream ois =
new ObjectInputStream(bis);
al = (ArrayList)ois.readObject();
ois.close();
}
catch (Throwable e) {
System.err.println(e);
}
}
}

注意我们使用缓冲提高I/O操作的速度。
有比串行化更快的输出大量数据然后读回的方法吗?可能没有,除非在特殊的情况下。例如,假设你决定将文本输出为64位的整数而不是一组8字节。作为文本的长整数的最大长度是大约20个字符,或者说二进制表示的2.5倍长。这种格式看起来不会快。然而,在某些情况下,例如位图,一个特殊的格式可能是一个改进。然而使用你自己的方案而不是串行化的标准方案将使你卷入一些权衡。

除了串行化实际的I/O和格式化开销外(使用DataInputStream和 DataOutputStream), 还有其他的开销,例如在串行化恢复时的创建新对象的需要。

注意DataOutputStream 方法也可以用于开发半自定义数据格式,例如:

import java.io.*;
import java.util.*;

public class binary1 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("outdata");
BufferedOutputStream bos =
new BufferedOutputStream(fos);
DataOutputStream dos =
new DataOutputStream(bos);
Random rn = new Random();
final int N = 10;
dos.writeInt(N);
for (int i = 1; i <= N; i++) {
int r = rn.nextInt();
System.out.println(r);
dos.writeInt(r);
}
dos.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

和:

import java.io.*;

public class binary2 {
public static void main(String args[]) {
try {
FileInputStream fis =
new FileInputStream("outdata");
BufferedInputStream bis =
new BufferedInputStream(fis);
DataInputStream dis =
new DataInputStream(bis);
int N = dis.readInt();
for (int i = 1; i <= N; i++) {
int r = dis.readInt();
System.out.println(r);
}
dis.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}

这些程序将10个整数写入文件然后读回它们。&n

分享到:
评论

相关推荐

    ORACLE DBA 手册

    调整JAVA池缓冲区 26 PRE_PAGE_SGA 27 LOCK_SGA 27 use_indirect_data_buffers 28 pga_aggregate_target: 28 SGA_TARGET 28 调整表空间 30 避免动态空间管理Oracle数据库增长空间是就以区的单位扩展的,区由块组成,...

    UNIX-IBMAIX5L参考-性能管理指南.chm

    逻辑卷和磁盘 I/O 性能 监视磁盘 I/O 调整影响性能的逻辑卷属性 物理卷注意事项 卷组建议 重组逻辑卷 使用磁盘 I/O 调步 调谐逻辑卷条纹 使用裸磁盘 I/O 使用 sync/fsync 调用 设置 SCSI 适配器和磁盘设备队列限制 ...

    基于Netty和Python的face-recognition库实现的高性能的人脸识别服务器.完整项目代码 计算机毕设

    本文将从零开始写一个高性能支持高并发的人脸...如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100 次操作就释放这把锁,让别的线程有机会执行(这个次数可以通过 sys.setcheckinterval 来调整)。所以虽然 CPython

    AIX 5L V5.3 性能管理指南(中文)

    性能管理 &lt;br&gt;本主题为应用程序员、客户工程师、系统工程师、系统管理员、资深最终用户和系统程序员提供有关如何执行任务(例如评估和调整处理器、文件系统、内存、磁盘 I/O、NFS、JAVA 和通信 I/O 的性能)的...

    ORACLE9i_优化设计与系统调整

    §6.2.8 步骤8:优化I/O和物理结构 89 §6.2.9 步骤9:优化资源争用 89 §6.2.10 步骤10:优化所采用的平台 89 §6.3 应用优化方法 90 §6.3.1 设定明确的优化目标 90 §6.3.2 创建最少可重复测试 90 §6.3.3 测试...

    java_jsp项目源码_+SQL电量监视系统设计与实现(源代码+论文).rar

    1. 实时监控:系统通过定时任务每隔一段时间(如5分钟)自动采集数据库的电量数据,包括CPU使用率、内存使用率、磁盘I/O、网络I/O等关键指标,实时展示在前端界面上,方便用户随时了解数据库的运行状态。 2. 历史...

    java面试题目与技巧1

    │ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...

    java面试题及技巧4

    │ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...

    java面试题以及技巧

    │ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...

    java 面试题 总结

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    java面试题及技巧3

    │ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...

    java面试题以及技巧6

    │ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...

    Wake:Wake是一个事件驱动的框架,基于SEDA,Click,Akka和Rx的思想

    从某种意义上说,它是通用的,旨在支持计算密集型应用程序以及高性能网络,存储和旧版I / O系统。 我们实现了Wake以支持高性能,可扩展的分析处理系统(“大数据”应用程序),并已使用它来实现控制平面逻辑(要求...

    JAVA程序设计教程

    I 第一章程序和程序设计 .......................................................................................................1 §1.1 什么是程序 ?....................................................

    wallet-android

    三重钱包ANDROID 迁移到本机android。 使用Android Studio。... 改进了套接字和I / O性能。 调整用户界面以适应更多手机。 用户界面现在更加友好。 更准确的单词。 更多的硬件功能。 增加稳定性。

    Tomcat面试专题及答案.pdf

    bio:传统的 Java I/O 操作,同步且阻塞 IO。 maxThreads=”150”//Tomcat 使用线程来处理接收的每个请求。这个值表示 Tomcat 可创建的最大的线程数。默认值 200。可以根据机器的时期性能和内存 大小调整,一般可以...

    event6:Kassel Code Meetup Tech Talk No.6 18.3.2015 http

    这意味着一方面可以使用未使用的资源,另一方面可以分配网络中 I/O 的负载。 本讲座旨在对该技术进行实用的介绍,并以 GlusterFS 为例,展示可能的应用场景是什么样的。 LibGDX游戏引擎-Tobi libGDX 是一个 Java...

    数据库优化设计方案.doc

    数据库中数据规范化的优 点是减少了数据冗余,节约了存储空间,相应逻辑和物理的I/O次数减少,同时加快了增 、删、改的速度。但是一个完全规范化的设计并不总能生成最优的性能,因为对数据库 查询通常需要更多的连接...

    Oracle数据库管理员技术指南

    8.8.1 怎样查找和避免 I/O 热点 8.8.2 使用原始文件系统 8.9 生成优化程序统计数据 8.9.1 使用 DBMS_UTILITY.ANALYZE _SCHEMA收集统计数据 8.9.2 使用 DBMS_UTILITY.ANALYZE _DATABASE 收集统计数据 8.9.3 ...

Global site tag (gtag.js) - Google Analytics