1. Trang chủ
  2. » Luận Văn - Báo Cáo

Tiểu luận môn điện toán đám mây SONG SONG HÓA LỚP BÀI TOÁN DẠNG CHIA ĐỂ TRỊ BẰNG JAVA FORK JOIN FRAMEWORK

19 583 0

Đ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

Định dạng
Số trang 19
Dung lượng 81,25 KB

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

Nội dung

Lời mở đầuKhi phần cứng máy tính ngày càng trở nên mạnh hơn, khi chip CPU của máy tính cá nhân ngày càng nhỏ và chứa nhiều CPU hơn cùng khả năng tính toán mạnh mẽ hơn thì một trong những

Trang 1

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN

-VÕ THÀNH NHÂN

SONG SONG HÓA LỚP BÀI TOÁN DẠNG CHIA ĐỂ TRỊ

BẰNG JAVA FORK/JOIN FRAMEWORK

MSHV: CH1301103

TIỂU LUẬN MÔN HỌC: Điện toán lưới và đám mây GVHD: PGS.TS Nguyễn Phi Khứ

TP Hồ Chí Minh

Tháng 6 - 2014

Trang 2

M c l c ục lục ục lục

1 Sơ lược về Java Fork/Join framework 3

1.1 Nguồn gốc hình thành 3

1.2 Thuật toán Fork/join điển hình 3

1.3 Cơ chế hoạt động 4

2 Ứng dụng 8

2.1 Tìm số hạng a n trong dãy số Fibonacci với n cho trước 8

2.2 Sắp xếp mảng số nguyên bằng thuật toán Quicksort 10

2.3 Nhân hai ma trận vuông bằng thuật toán Strassen 12

3 Kết luận 17

4 Tài liệu tham khảo 18

Trang 3

Lời mở đầu

Khi phần cứng máy tính ngày càng trở nên mạnh hơn, khi chip CPU của máy tính cá nhân ngày càng nhỏ và chứa nhiều CPU hơn cùng khả năng tính toán mạnh mẽ hơn thì một trong những đòi hỏi được đặt ra là các chương trình phần mềm phải tận dụng được sức mạnh tính toán này để gải quyết một cách hiệu quả các bài toán thực tế Ngày nay có rất nhiều vấn đề yêu cầu những khối lượng tính toán rất lớn như: xử lý ảnh, xử lý ngôn ngữ tự nhiên, data mining, truy vấn các cơ sở dữ liệu đa phương tiện, các hệ thống thời gian thực, thực tại ảo… Để giải quyết những vấn đề này xu hướng hiện nay là áp dụng các kĩ thuật lập trình song song vào các chương trình phần mềm để đạt được hiệu quả tốt hơn Tuy nhiên lập trình song song đòi hỏi nhiều kĩ thuật và khó hơn nhiều so với lập trình tuần tự Nên tự nhiên phát sinh nhu cầu xây dựng các ngôn ngữ lập trình, khuôn khổ(framework), thư viện chuẩn để hỗ trợ người lập trình xây dựng các chương trình song song dễ dàng và đơn giản hơn Rất nhiều ngôn ngữ, khuôn khổ, thư viện dạng này

đã ra đời và đáp ứng rất tốt nhu cầu trên như: Occam, Java thread, Pthread, PVM, MPI, Cilk…

Từ phiên bản 1.7 Java đã bổ sung gói thư viện java.util.concurrent vào nền tảng Java SE

để hỗ trợ người lập trình xây dựng các chương trình trong môi trường đa xử lý được dễ dàng hơn Đặc biệt là đưa vào khuôn khổ Fork/Join nhằm trợ giúp song song hóa các lớp bài toán “chia để trị” một cách dễ dàng và hiệu quả Nội dung của tiểu luận là tập trung giới thiệu khuôn khổ này cùng một số ví dụ minh họa cách song song hóa bài toán theo phong cách fork/join của Java

Trang 4

1 S l ơ lược về Java Fork/Join framework ược về Java Fork/Join framework c v Java Fork/Join framework ề Java Fork/Join framework

1.1 Nguồn gốc hình thành

- Khuôn khổ(framework) Fork/Join là một phần của JSR-166 nhằm cung cấp những class tiện ích, hỗ trợ những chức năng thông dụng cho lập trình tương tranh(concurrent programming) Nó bao gồm một vài khuôn khổ nhỏ, chuẩn và có khả năng mở rộng cũng như những class cài đặt những chức năng phổ dụng, tẻ nhạt, thường xuyên xuất hiện trong lập trình tương tranh

- Khuôn khổ Fork/Join là một cài đặt cho interface ExecutorService mà giúp người lập trình tận dụng lợi thế các hệ thống đa xử lý(multiple processsors) Nó được thiết kế cho các bài toán có thể chia thành các bài toán nhỏ hơn một các đệ quy Mục đích

là để sử dụng năng lực của tất cả các bộ xử lý trong hệ thống để nâng cao hiệu năng giải bài toán Như vậy khuôn khổ Fork/Join rất thích hợp cho các lớp bài toán mà có thể giải được bằng các thuật toán “chia để trị”( divide−and−conquer algorithms)

1.2 Thuật toán Fork/join điển hình

- Tính song song trong khuôn khổ Fork/Join là một trong những kĩ thuật thiết kế đơn giản và hiệu quả nhất để nhận được hiệu năng song song tốt Thuật toán tổng quát khi áp dụng cho các bài toán “chia để trị” có dạng sau đây:

Result solve(Problem problem)

{

If (problem là nhỏ)

giải trực tiếp problem else

{

independent-parts = chia problem thành những phần độc lập với mỗi part trong independent-parts // fork operation

tạo ra một fork/join subtask để gọi đệ quy solve(part) đợi tất cả các fork/join subtask hoàn tất // join operation

tổ hợp kết quả từ các fork/join subtask }

}

Trang 5

Các subtask trong thao tác fork là thực thi một cách song song và thao tác join sẽ ngăn không cho task hiện hành tiếp tục cho đến khi tất cả các subtask được hoàn tất Quá trình chia nhỏ bài toán sẽ lặp lại cho đến khi các bài toán con đủ nhỏ để giải một cách tuần tự, đơn giản

1.3 Cơ chế hoạt động

- Thiết kế tổng quát của khuôn khổ Fork/Join là một biến thể “lấy trộm công việc”(work-stealing) kế thừa từ Cilk(một ngôn ngữ lập trình dựa trên ANSI C được phát triển từ năm 1994 tại phòng thí nghiệm khoa học máy tính của MIT) Kĩ thuật cài đặt chính gói gọn trong việc khởi tạo và quản lý hiệu quả các hàng đợi công việc(tasks queue) và các luồng làm việc(worker threads)

- Các chương trình Fork/join chia bài toán thành những phần độc lập nhỏ hơn vào các subtask và thực thi các subtask một cách song song Chúng ta đã biết Java hỗ trợ lập trình tương tranh(concurrent programming) và lập trình song song bằng các luồng(thread) nên sẽ là tự nhiên nếu nghĩ rằng mỗi subtask sẽ chạy trong một luồng riêng Tuy nhiên, khuôn khổ Fork/join không làm như thế vì những lí do sau đây:

 Các Fork/join task cần quản lý các yêu cầu đồng bộ hóa(synchonization) một cách đơn giản Các đồ thị tính toán được sản sinh ra bởi các fork/join task cần có một chiến lược lập lịch hiệu quả hơn các luồng sao cho tận dụng tối đa các CPU hiện

có trong hệ thống Thêm vào đó các fork/join task không cần phải block trừ khi nó đợi các subtask hoàn tất Như vậy các chi phí phát sinh do việc quản lý và theo dõi các luồng bị block sẽ không còn

 Bởi vì cách tiếp cận của khuôn khổ fork/join là chia bài toán ban đầu thành những bài toán độc lập nhỏ hơn nên sẽ phát sinh tình trạng là có khá nhiều các fork/join task Nếu mỗi fork/join task chạy trong một luồng riêng rẽ thì có khả năng sẽ làm cho hệ thống chạy rất chậm hoặc bị treo do có quá nhiều luồng được sinh ra Đó là chưa kể chi phí để khởi tạo và quản lý luồng có thể sẽ lớn hơn thời gian tính toán cần thiết của task đó

Trang 6

- Từ hai lý do nêu trên ta thấy rằng các luồng là quá nặng nề và cồng kềnh cho các khuôn khổ Fork/join Nên cần thiết có một cách tiếp cận khác cho khuôn khổ này Những người thiết kế khuôn khổ Fork/join đã đưa ra một thiết kế như sau:

 Tạo ra một hồ chứa các luồng làm việc (pool of worker threads) Mỗi luồng làm việc trong hồ chứa này chính là một luồng Java chuẩn(standard thread) và nó sẽ có một hàng đợi chứa các fork/join task Thông thường thì số lượng các luồng trong

hồ tương ứng với số lượng CPU của hệ thống Sau đó mỗi luồng sẽ được ánh xạ vào một CPU nhất định và thực thi các fork/join task trong hàng đợi của nó

 Hàng đợi đề cập ở trên là một hàng đợi hai đầu(double−ended queue) dùng để lập lịch, quản lý và thực thi các fork/join task thông qua luồng làm việc(worker thread) Cơ chế lập lịch này dựa vào một khái niệm gọi là “lấy trộm công việc”(work-stealing) Đây không phải là một khái niệm mới mà nó đã xuất hiện trong Cilk Về cơ bản có thể hiểu cơ chế này như sau:

 Những fork/join subtask được sinh ra từ một fork/join task sẽ được đưa vào hàng đợi của luồng đang thực hiện fork/join task đó

 Các worker thread chọn fork/join task từ hàng đợi để thi hành theo quy tắc LIFO(Last In First Out) Khi một worker thread hết task trong hàng đợi của nó, nó sẽ cố gắng “trộm” một fork/join task từ một worker thread khác theo quy tắc FIFO(First In First Out) nghĩa là chúng luôn làm thao tác ở hai đầu khác nhau của hàng đợi Cách làm này vừa hạn chế tối xung đột khi hai thread cùng truy cập hàng đợi mà còn tận dụng tính chất đệ quy của nguyên lý “chia để trị” khiến cho các fork/join task

sẽ có cơ hội được phân rã thành những task nhỏ hơn bởi luồng trộm việc(stealing thread)

 Khi một worker thread bắt gặp thao tác join, nó sẽ thi hành một fork/join task khác(lấy trong hàng đợi hay “trộm” từ luồng làm việc khác) cho đến khi task đích thông báo hoàn tất Tất cả các fork/join task khác sẽ chạy mà không bị blocking Nếu một worker thread không có task thực thi và gặp thất bại khi “trộm” task từ worker thread khác nó sẽ

Trang 7

sleep, yields hoặc bị điều chỉnh lại độ ưu tiên sau đó sẽ lại cố gắng

“trộm” task Quá trình này lặp lại cho đến khi tất cả các worker thread đều rãnh rỗi Trong trường hợp như vậy, tất cả các worker thread trong

hồ sẽ bị block cho dến khi có một fork/join task mới xuất hiện

 Tạo ra một abstract class tên là ForkJoinTask để biễu diễn cho một fork/join task Class này có một abstract method quan trọng là exec được gọi khi thi hành một fork/join task Để hỗ trợ người lập trình nhanh chóng tạo lập các fork/join task thì

từ class này có 2 class kế thừa là RecursiveAction và RecursiveTask Hai class này định nghĩa lại tất cả các abstract method trong class ForkJoinTask và chúng thêm vào một abstract method mới tên là compute(được gọi trong method exec) Như vậy để tạo ra một fork/join task thì người lập trình chỉ cần tạo ra một class kế thừa

Trang 8

từ một trong hai class RecursiveAction hoặc RecursiveTask và định nghĩa lại method compute

 Tạo ra một class ForkJoinPool để quản lý hồ chứa các luồng làm việc(pool of worker thread), khởi tạo sự thực thi của một fork/join task khi nó được triệu gọi từ một luồng bên ngoài(như trong hàm main chẳng hạn)

Trang 9

2 Ứng dụng

Trong phần này sẽ trình bày một số ví dụ minh họa cách song song hóa một bài toán với Java Fork/Join framework Với mỗi bài toán sẽ gồm 2 phần:

- Mã nguồn cài đặt cho phiên bản song song cùng một số giải thích(nếu cần thiết)

- Một bảng trình bày thời gian chạy cho 2 phiên bản: tuần tự và song song(ở mỗi lần chạy cả hai phiên bản đều chạy cùng một bộ dữ liệu) Tất cả thời gian chạy đều được tính bằng đơn vị giây Các thử nghiệm chạy trên một máy Intel core i5 có 4 bộ xử lý

Để xem toàn bộ mã nguồn, có thể tham khảo các file java kèm theo Toàn bộ mã nguồn được biên dịch bằng jdk 1.8 update 5

2.1 Tìm số hạng an trong dãy số Fibonacci với n cho trước

- Xét bài toán: cần tìm số hạng an trong dãy số Fibonacci với n cho trước Ta có thể song song hóa bài toán này như sau:

class FibonacciForkJoinTask extends RecursiveAction

{

static final int threshold = 13;

volatile int number; // value of a n

public FibonacciForkJoinTask(int n)

{

number = n;

}

@Override

public void compute()

{

int n = number;

if (n <= threshold)

number = seqFib(n);

else

{

FibonacciForkJoinTask f1 = new FibonacciForkJoinTask(n - 1);

FibonacciForkJoinTask f2 = new FibonacciForkJoinTask(n - 2);

Trang 10

invokeAll(f1, f2);

number = f1.number + f2.number;

}

}

private int seqFib(int n)

{

if (n <= 1)

return n;

return seqFib(n-1) + seqFib(n-2);

}

}

Bảng sau đây là kết quả mười lần chạy thực nghiệm khi phát sinh ngẫu nhiên n từ 30 –

50 Ta thấy là trong đa số trường hợp phiên bản song song luôn chạy nhanh hơn bản tuần

tự gần ba lần

Bảng 2.1 Kết quả chạy thực nghiệm cho bài toán tìm số hạng an trong dãy Fibonacci khi

biết n

N Serial execution time Paralell execution time

Speedu p

Trang 11

2.2 Sắp xếp mảng số nguyên bằng thuật toán Quicksort

- Xét bài toán: cần sắp xếp một mảng các số nguyên bằng thuật toán Quicksort Ta

có thể song song hóa bài toán này như sau:

class ForkJoinQuicksortTask extends RecursiveAction

{

private static final int SERIAL_THRESHOLD = 0x1000;

private final int[] a;

private final int left;

private final int right;

public ForkJoinQuicksortTask(int[] a)

{

this(a, 0, a.length - 1);

}

private ForkJoinQuicksortTask(int[] a, int left, int right)

{

this.a = a;

this.left = left;

this.right = right;

}

@Override

protected void compute()

{

if (right - left < SERIAL_THRESHOLD)

Arrays.sort(a, left, right + 1);

else

{

int[] indexs = partition(a, left, right);

int curLeft = indexs[0], curRight = indexs[1];

ForkJoinTask t1 = null;

if (left < curRight)

t1 = new ForkJoinQuicksortTask(a, left, curRight).fork();

if (curLeft < right)

new ForkJoinQuicksortTask(a, curLeft, right).invoke();

if (t1 != null)

t1.join();

}

}

private int[] partition(int[] a, int left, int right)

{

// chose middle value of range for our pivot

int pivotValue = a[(left + right) >>> 1];

while (left <= right)

{

while (a[left] < pivotValue)

++left;

Trang 12

while (a[right] > pivotValue)

right;

if (left <= right)

{

int tmp = a[left];

a[left] = a[right];

a[right] = tmp;

left++;

right ;

}

}

return new int[] { left, right };

}

}

Bảng sau đây là kết quả thực nghiệm của mười lần chạy Mỗi lần sắp xếp một mảng nguyên ngẫu nhiên có một trăm triệu phần tử Phiên bản song song hóa với Fork/Join luôn chạy nhanh hơn gấp ba lần so với phiên bản tuần tự

Bảng 2.2 Kết quả chạy thực nghiệm sắp xếp mảng số nguyên một trăm triệu phần tử bằng

thuật toán Quicksort

Serial execution time Paralell execution time Speedup

Trang 13

2.3 Nhân hai ma trận vuông bằng thuật toán Strassen

- Xét bài toán: cần nhân hai ma trận vuông bằng thuật toán Strassen Để đơn giản chỉ xét các ma trận vuông có kích thước là một lũy thừa của hai Ta có thể song song hóa bài toán này như sau:

class StrassenForkJoin extends RecursiveAction

{

public int[][] result;

int[][] a, b;

int n;

public StrassenForkJoin(int[][] a, int[][] b, int n)

{

this.a = a;

this.b = b;

this.n = n;

}

private int[][] sumMatrix(int[][] a, int[][] b, int n)

{

int[][] res = new int[n][n];

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

for (int j = 0; j < n; ++j)

{

res[i][j] = a[i][j] + b[i][j];

}

return res;

}

private int[][] subMatrix(int[][] a, int[][] b, int n)

{

int[][] res = new int[n][n];

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

for (int j = 0; j < n; ++j)

{

res[i][j] = a[i][j] - b[i][j];

Trang 14

}

return res;

}

private int[][] mulMatrix(int[][] a, int[][] b, int n)

{

int[][] res = new int[n][n];

int t = 0;

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

for (int j = 0; j < n; ++j)

{

t = 0;

for (int k = 0; k < n; ++k)

t += a[i][k]*b[k][j];

res[i][j] = t;

}

return res;

}

private void fillMatrix(int[][] a, int[][] b, int nB, int row, int col) {

int r, c;

r = (row-1)*nB;

c = (col-1)*nB;

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

for (int j = 0; j < nB; ++j)

a[r + i][c + j] = b[i][j];

}

private int[][] extractMatrix(int[][] a, int n, int row, int col)

{

Trang 15

int[][] res = new int[n/2][n/2];

int r, c;

r = (row-1)*n/2;

c = (col-1)*n/2;

for (int i = 0; i < n/2; ++i)

for (int j = 0; j < n/2; ++j)

res[i][j] = a[r + i][c + j];

return res;

}

@Override

public void compute()

{

if (n <= 2)

result = mulMatrix(a, b, n);

else

{

int[][] a11, a22, a21, a12, b21, b22, b11, b12, c11, c12, c21, c22;

StrassenForkJoin t1, t2, t3, t4, t5, t6, t7;

a12 = extractMatrix(a, n, 1, 2);

a22 = extractMatrix(a, n, 2, 2);

b21 = extractMatrix(b, n, 2, 1);

b22 = extractMatrix(b, n, 2, 2);

t1 = new StrassenForkJoin(subMatrix(a12, a22, n/2), sumMatrix(b21, b22, n/2), n/2);

a11 = extractMatrix(a, n, 1, 1);

b11 = extractMatrix(b, n, 1, 1);

t2 = new StrassenForkJoin(sumMatrix(a11, a22, n/2), sumMatrix(b11, b22, n/2), n/2);

a21 = extractMatrix(a, n, 2, 1);

b12 = extractMatrix(b, n, 1, 2);

Ngày đăng: 19/05/2015, 20:43

HÌNH ẢNH LIÊN QUAN

Bảng sau đây là kết quả mười lần chạy thực nghiệm khi phát sinh ngẫu nhiên n từ 30 – - Tiểu luận môn điện toán đám mây SONG SONG HÓA LỚP BÀI TOÁN DẠNG CHIA ĐỂ TRỊ BẰNG JAVA FORK JOIN FRAMEWORK
Bảng sau đây là kết quả mười lần chạy thực nghiệm khi phát sinh ngẫu nhiên n từ 30 – (Trang 10)
Bảng 2.2 Kết quả chạy thực nghiệm sắp xếp mảng số nguyên một trăm triệu phần tử bằng - Tiểu luận môn điện toán đám mây SONG SONG HÓA LỚP BÀI TOÁN DẠNG CHIA ĐỂ TRỊ BẰNG JAVA FORK JOIN FRAMEWORK
Bảng 2.2 Kết quả chạy thực nghiệm sắp xếp mảng số nguyên một trăm triệu phần tử bằng (Trang 12)
Bảng sau đây là kết quả chạy thực nghiệm với các ma trận ngẫu nhiên có kích thước từ 2, - Tiểu luận môn điện toán đám mây SONG SONG HÓA LỚP BÀI TOÁN DẠNG CHIA ĐỂ TRỊ BẰNG JAVA FORK JOIN FRAMEWORK
Bảng sau đây là kết quả chạy thực nghiệm với các ma trận ngẫu nhiên có kích thước từ 2, (Trang 17)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w