1. Trang chủ
  2. » Công Nghệ Thông Tin

Tối ưu hóa lập trình Java

67 858 6
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tối ưu hóa lập trình Java
Trường học Trường Đại Học Công Nghệ Thông Tin
Chuyên ngành Công Nghệ Thông Tin
Thể loại Bài luận
Thành phố Hà Nội
Định dạng
Số trang 67
Dung lượng 1,44 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Chuyển đổi Characters  Bytes  Một giải pháp phần mềm mang tính khái quát có thể ảnh hưởng đến hiệu năng của hệ thống.. Chính điều này mâu thuẫn trưc tiếp với tính tái sử dụng trong thi

Trang 1

Java’s Performance

Trang 2

 Hiệu năng trong các lớp Collection

 Catching trong tối ưu hóa

 Java I/O Stream

Trang 3

chương trình

Trang 5

Yêu cầu tối ưu hóa

 Những yêu cầu trước khi tối ưu hóa

 Code optimize được xem là một quá trình biến đổi một source code cũ sang một source code mới Việc chuyển đổi này có

những đặc tính:

• Giữ được tính chính xác

• Hiệu quả hơn cái code cũ

• Code optimize thường mất đi tính khái quái và kém khả năng sử

dụng lại Đơn giản là do nó thu hẹp phạm vi và tập trung vào vấn

đề cẩn phải giải quyết

• Code mới thường phức tạp hơn code cũ Nó có tính phức tạp, khó

hiểu, khó bảo trì,khó sửa đổi & mở rộng

Trang 6

Yêu cầu tối ưu hóa

 Những yêu cầu trước khi tối ưu hóa

 Với những lý luận này, tối ưu hóa phần mềm là một công việc tương đối rủi ro Nó có thể tác động không tốt đến những tiêu chí khác quan trọng không kém của phần mềm vì vậy, cần phải

có sự cân nhắc khi thực hiện:

• Cần profile hóa đoạn mã cũ

• Xem xét những yếu tố trả về khi thực hiện tối ưu.

Trang 7

Xử lý xâu kí tự

 Xử lý xâu chuỗi là một vấn đề thường xuyên gặp khi lập trình Java, đặc

biệt là trong các ứng dụng Web

( String, StringBuffer hay StringTokenizer )

Các vấn đề tối ưu trong xâu kí tự:

1 Ghép nối xâu chuỗi

2 Quản lý đối tượng

4 Chuyển đỗi kí tự & byte

5 charAt() & startWidth()

6 StringBuffer’s Capacity

Trang 8

Xử lý xâu kí tự

1. Ghép nối xâu chuỗi

ví dụ: String p = a+b; ( có bao nhiêu đối tượng được tạo ra ? )

 String p = (new StringBuffer()).append(a).append(b).toString()

String s = new String();

// <+++ Start timing

long start = System.currentTimeMillis();

for (int i = 0; i < 10000; i++) {

for (int i = 0; i < 10000; i++) { s.append("a");

}

// <+++ Stop timing long stop = System.currentTimeMillis(); // Result: 8 mili s

Nhận xét : Sử dụng StringBuffer với các thao tác ghép nối, thay đổi giá trị xâu chuỗi.

Trang 10

// Compare two identical strings

public class Equals_1 {

public static void main(String args[]) {

String p = "HelloWorlD";

// <+++ Start timing long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) {

s.equals(p);

} // <+++ Stop timing long stop = System.currentTimeMillis(); }}

Trang 11

Xử lý xâu kí tự

3 So sánh chuỗi

// Compare two strings of different length

public class Equals_3 {

public static void main(String args[]) {

String s = "HelloWorld";

String p = "HelloWorld1";

// <+++ Start timing

long start = System.currentTimeMillis();

for (int i = 0; i < 10000000; i++) {

Trang 12

Xử lý xâu kí tự

4. Chuyển đổi Characters Bytes

public class StringGetBytes {

public static void main(String args[]) {

String s = "HelloWorld";

// <+++ Start timing

long start = System.currentTimeMillis();

for (int i = 0; i < 1000000; i++) {

int i;

byte[] bytebuf = new byte[size];

for (i = 0; i < size; i++) { bytebuf = (byte) buf.charAt(i);

} return bytebuf;

} public static void main(String args[]) { String s = "HelloWorld";

long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) {

byte[] b = asciiGetBytes(s);

} long stop = System.currentTimeMillis(); System.out.println( " time = " + (stop - start) ); }}

// Result : 2.500 mili s

Trang 13

Xử lý xâu kí tự

4. Chuyển đổi Characters Bytes

 Một giải pháp phần mềm mang tính khái quát có thể ảnh hưởng đến hiệu năng của hệ thống

Một điều cơ bản của tối ưu hóa là hãy thu hẹp phạm vi vấn đề giải quyết Chính điều này mâu thuẫn trưc tiếp với tính tái sử dụng trong thiết kế phần mềm theo hướng đối tượng

 Mỗi một kí tự Unicode có thể chuyển thành 2,3 byte Tuy nhiên, nếu chỉ xem xét vấn đề

giải quyết đối với những kí tự trong bảng mã ACSII - một tập hợp con nhỏ hơn của Unicode…

 Trong ASCII, mỗi một kí tự được chuyển đổi thành một byte, bởi việc cắt đi một trong số

hai byte biểu diễn theo Unicode

 Chính những thao tác chuyển đổi này sẽ ảnh hướng đến tính phức tạp + hiệu năng hệ

thống nếu chúng ta chỉ cần sử dụng đến những kí tự trong bảng mã ACSII

Nhận xét :

Muốn tăng hiệu năng, hãy thu hẹp phạm vi xử lý và chỉ tập trung vào vấn đề

cần phải giải quyết  Hạn chế các thao tác dư thừa Ví dụ: charAt()

Trang 14

Xử lý xâu kí tự

5 charAt() & startsWith()

public static byte[] asciiGetBytes(String

buf) {

int size = buf.length();

int i;

byte[] bytebuf = new byte[size];

for (i = 0; i < size; i++) {

// String begins

// It could be substring of a // larger String

}

if (s.startsWith("a")) { } if ('a' == s.charAt(0)) { }

Trang 15

Xử lý xâu kí tự

6 StringBuffer’s Capacity

Để định nghĩa một đối tượng StringBuffer chúng ta có hai cách:

StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer(XX);

 Khởi tạo với kích thước mặc định 16

Trang 16

Pure Overhead

Giới thiệu vấn đề:

Việc tối ưu hóa đỏi hỏi phải cân bằng được các yếu tố có khả năng xung đột lẫnnhau trong một phần mềm (tính mềm dẻo, khả năng bảo trì, giá cả, khả năng tái sửdụng ).Tuy nhiên vẫn có những trường hợp tối ưu mà không làm ảnh hưởng đếnnhững tiêu chí khác ( pure overhead )

Trang 17

Pure Overhead

1 Những tính toán dư thừa:

public class Trace {

private static boolean loggingIsOn = false;

public static void log (String msg) {

if (loggingIsOn == true) System.out.println(msg); } public static void setLoggingIsOn(boolean newState) {

loggingIsOn = newState; } public static boolean logging() {

return loggingIsOn;

} }

Lớp Tracing gồm một biến private static : loggingIsOn giám sát trạng thái của

ứng dụng bằng cách in ra thông báo msg khi có giá trị bằng true Ví dụ Tracing mộtbiến nguyên i:

public void doIntTrace(int i) {

Trace.log("Enter doIntTrace() Input arg is " + i);

myInt = i+1;

Trace.log("Exit doIntTrace()"); }

Trang 18

Pure Overhead

1 Những tính toán dư thừa

public void doInt(int i) {

myInt = i+1;

}

public void doIntTrace(int i) { Trace.log("Enter doIntTrace() Input arg is " + i);

Trang 19

Pure Overhead

1 Những tính toán dư thừa

Hướng giải quyết: Kiểm tra giá trị biến trước khi thực hiện truyền tham số:

public void doIntTrace2(int i) {

if (Trace.logging()) Trace.log("Enter doIntTrace2() Input arg is " + i); myInt = i+1;

if (Trace.logging()) Trace.log("Exit doIntTrace2()");

}

Trang 20

Pure Overhead

2 Tránh dư thừa trong việc tạo đối tượng

void f() { int i;

Date x = new Date();

// Date x is constructed outside

// the scope where it is used

if ( ) { // Date object x only used here }

}

void f() { int i;

if ( ) { Date x = new Date();

// Date x is constructed inside the // scope where it is used

// Date object x only used here }

}

Nếu điều kiện if là false thì việc tạo ra

biến x là dư thừa:

- Cấp phát đối tượng mới

- Thực thi khởi tạo giá trị cho đối tượng

- Thu dọn khi đối tượng không còn sử

dụng

Trang 21

Pure Overhead

3 Nguyên tắc 80-20

Nguyên tắc 80-20 chỉ ra rằng : 20% thời giạn bạn code đã tạo ra những dòng lệnhmới và 80% thời gian để fix những bug trong một phần mềm, 80% thời gian thực thicủa một phần mềm bị chiếm bởi thời gian thực thi của 20% dòng lệnh nào đó Vấn

đề là làm sao để có thể tìm ra được phần 20% đó, và giải quyết vấn đề đó cho thậttốt

Ví dụ:

Một đặc tả HTTP mô tả những HTTP request có thể có mà một Web server cầnphải xử lý Các HTTP request này không phải là ngẫu nhiên , nói cách khác đa sốchúng đều có những điểm chung nhất định

Nếu như ban biết rằng, đa số các trình duyệt mà client sử dụng đều chỉ tập trungtrên môt số loại như I.E , Mozzila thì chúng ta có thể tập trung vào việc xử lý nhữngrequest đến từ các loại trình duyệt này, trước khi đưa ra những xử lý chung cho tất

cả các loại trình duyệt khác nhau

Trang 22

Pure Overhead

3 Nguyên tắc 80-20

Trong HTTP request, trường HTTP Accept header xác định những định dạng nộidung mà trình duyệt có thể xử lý được Trong đặc tả HTTP, nó cho phép "Accept“header có thể sử dụng cả chữ in hoa hoặc chữ in thường, vì vậy, khi xử lý chuỗi kí

tự "Accept", chúng ta phải viết :

if (headerName.equalsIgnoreCase("Accept:")) { // This is the Accept header

}Tuy nhiên, so sánh như vậy sẽ ảnh hưởng đến hiệu năng Tại sao chúng ta khôngnghĩ đến một giải pháp tối ưu hơn : tập trung xử lý trước tiên đối với những "Accept:" của I.E, hay Mozzila, trước khi đưa ra một xử lý chung, theo đúng đặc tả

if (headerName.equals("Accept:") || headerName.equalsIgnoreCase("Accept:")) {

// This is the Accept header Do something with it

}

Trang 23

Vector & Hashtable Các vấn đề:

 Vector Add & Remove

 Vector’s Capacity

 Vector Enumeration

 Xây dựng lớp Vector hiệu quả

 Phương pháp sử dụng hàm API

 Các tham số của Hashtable

 Nâng cao tốc độ hashCode() & equals()

Trang 24

Vector & Hashtable

1 Vector Add & Remove

Đối tượng Vector cung cấp cho chúng ta rất nhiều cách để bổ sung thêm một phần

Đánh giá hiệu năng giữa các phương thức

Phương thức addElement() có tốc độ thực thi nhanh hơn add(), do nó trả về

giá trị void, trong khi add() trả về một giá trị boolean

Trang 25

Vector & Hashtable

2 Vector’s Capacity

Khái niệm Vector’s Capacity giống như trong StringBuffer

Quá trình mở rộng của Vector, đòi hỏi bộ nhớ phải cấp phát một mảng mới, và copy

dữ liệu từ mảng cũ sang mảng mới, xóa mảng cũ đi Chính vì thế, nó cũng sẽ tácđộng tương đối đến hiệu quả thực thi của phần mềm

 Giải quyết: thay thế khởi tạo mặc định

Vector v = new Vector()

bằng Vector v = new Vector(x),với x là một giá trị ước lượng

Ngoài ra, còn một tham số nữa có thể sử dụng là mức độ gia tăng phần tử trong quátrình mở rộng, với mục đích ở đây là giảm thiểu hóa việc tác động hiệu năng khiVector bắt buộc phải mở rộng

Ví dụ: Vector v = new Vector(100,25);

Trang 26

Vector & Hashtable

3 Vector Enumeration

int size = v.size();

for (int i = 0; i < size; i++) {

//result : method 1 is better than method 2

for (Enumeration enum = v.elements(); enum.hasMoreElements(); ) {

s = (String) enum.nextElement(); // Do something

}

for (Enumeration enum = v.elements();; ) {

s = (String) enum.nextElement(); // Do something

} } catch (NoSuchElementException e) {}

Trang 27

Vector & Hashtable

4 Xây dựng lớp Vector hiệu quả

Xây dựng một lớp PVector hay thể cho Vector, chỉ tập trung vào tính hiệu quả của việcthực thi

public class PVector {

protected Object elementData[];

protected int elementCount;

public PVector(int initialCapacity) { elementData = new Object[initialCapacity];}

private void ensureCapacity(int minCapacity) {

int oldCapacity = elementData.length;

if (minCapacity > oldCapacity) {

Object oldData[] = elementData;

int newCapacity = oldCapacity * 2;

if (newCapacity < minCapacity) { newCapacity = minCapacity; }

elementData = new Object[newCapacity];

System.arraycopy(oldData, 0, elementData, 0, elementCount);

} }

Trang 28

Vector & Hashtable

4 Xây dựng lớp Vector hiệu quả

public int size() { return elementCount; }

public Object elementAt(int index) {

return elementData[index];

}

public void setElementAt(Object obj, int index) { elementData[index] = obj; }

public void addElement(Object obj) {

ensureCapacity(elementCount + 1);

elementData[elementCount++] = obj;

}

public void removeAllElements() {

for (int i = 0; i < elementCount; i++)

elementData = null;

elementCount = 0;

}

Trang 29

Vector & Hashtable

4 Xây dựng lớp Vector hiệu quả

public Object remove() {

Object oldValue = elementData[ elementCount];

elementData[elementCount] = null; // Let gc do its work return oldValue;

}

public String toString() {

int max = elementCount -1;

StringBuffer buf = new StringBuffer();

Trang 30

Vector & Hashtable

5 Phương pháp sử dụng hàm API

{

String s1 = "HelloWorld";

Vector v = new Vector(1000);

long start = System.currentTimeMillis();

for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 1000; j++) {

// Populate vector with 1,000 elements

v.addElement(s1); }

for (int size = v.size(); size > 0; ) {

String s2 = (String) v.elementAt(size-1);

v.removeElementAt( size); }

}

long stop = System.currentTimeMillis();

// <++++++++ Stop timing here

} // result : 1.600 mili s

{String s1 = "HelloWorld";

Vector v = new Vector(1000);

long start = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 1000; j++) { // Populate vector with 1,000 elements v.addElement(s1); }

for (int size = v.size(); size > 0; ) { String s2 = (String) v.remove(size); long stop = System.currentTimeMillis(); // <++++++++ Stop timing here

} // result : 1.180 mili s

Trang 31

Vector & Hashtable

5 Phương pháp sử dụng hàm API

Giả sử rằng, có một đối tượng Hashtable để lưu giữ những servlet data bởi các key

- servlet name ( một xâu kí tự ) Khi yêu cầu một serlvet data, chúng ta đưa ra servletname tương ứng, nếu serlvet data không được tìm thấy, chúng ta phải tạo một đầu vàocho nó, đưa giá trị vào bảng cho các lần truy cập về sau Công việc này được thực thiđơn giản như sau :

Trang 32

Vector & Hashtable

5 Phương pháp sử dụng hàm API

Phương án giải quyết:

if ( (se = (ServletEntry) table.get(servletName)) != null) {

Trang 33

Vector & Hashtable

6 Các tham số của Hashtable

 Hashtable là một mảng các Bucket.Mỗi Bucket gồm có mỗi danh sách theo kiểu

dữ liệu link-list các cặp key-value

 Khi một cặp key-value được chèn vào Hashtable, nó được map tới một bucket nhất

định thông qua một hàm mã hóa gọi là hashCode()

 Khi lấy một giá trị tương ứng với một Key:

 Giá trị Key nào được đưa tới đầu vào của hàm hashCode(), trả về index của

Bucket tương ứng

 Tìm kiếm tuyến tính được thực hiện trên link-list của Bucket này để xác định vị

trị ứng với key và lấy kết quả tại đó đưa về Sự so sánh giữa các key trong link-list được thực hiện qua phương thức equals()

Các yếu tố ảnh hưởng đến tính hiệu năng :

- Tìm kiếm theo tuyến tính Chúng ta phải giảm đi chiều dài của link-list trong Bucket đến mức tối thiểu

- Hiệu năng của hàm hashCode()

- Tác động của so sánh theo phương thức equals()

Trang 34

Vector & Hashtable

6 Các tham số của Hashtable

Phương án giải quyết:

a) Với hashCode()

- HashCode(), phải đảm bảo các key phải được phân bố đều qua các Bucket, tránh

trường hợp tập trung các key vào trong cùng Bucket

- Hàm hashCode() quét qua mỗi kí tự trong các đối tượng key để tạo ra giá trị index

xác định Bucket tương ứng  tốc độ hashCode() tỉ lệ nghịch với chiều dài String

- Chiều dài của link-list gồm hai tham số , “capacity” và "load factor" Đối tượng

Hashtable, khởi đầu giá trị capacity là số lượng các bucket trong nó "Load factor" xác định số lượng các phần tử (số cặp key-value) mà Hashtable có thể chứa, khi vượt quá giới hạn thì số lượng các Buckets sẽ tăng lên gấp đôi - quá trình này gọi

là "rehasing"

Ngày đăng: 09/05/2014, 16:49

TỪ KHÓA LIÊN QUAN

w