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

Nội dung

Tiểu luận môn học: Điện toán lưới và đám mây ĐẠ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 1 Tiểu luận môn học: Điện toán lưới và đám mây Mục lục 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 2 Tiểu luận môn học: Điện toán lưới và đám mây 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. 1. Sơ lược về 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. 3 Tiểu luận môn học: Điện toán lưới và đám mây - 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 } } 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. 4 Tiểu luận môn học: Điện toán lưới và đám mây 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 đó. - 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 5 Tiểu luận môn học: Điện toán lưới và đám mây 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ẽ 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. 6 Tiểu luận môn học: Điện toán lưới và đám mây • 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 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) 7 Tiểu luận môn học: Điện toán lưới và đám mây 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: 8 Tiểu luận môn học: Điện toán lưới và đám mây - 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 a n trong dãy số Fibonacci với n cho trước - Xét bài toán: cần tìm số hạng a n 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); invokeAll(f1, f2); number = f1.number + f2.number; } } private int seqFib(int n) 9 Tiểu luận môn học: Điện toán lưới và đám mây { 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 a n trong dãy Fibonacci khi biết n 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; 10 N Serial execution time Paralell execution time Speedu p 30 0.004 0.002 2.00 31 0.007 0.002 3.50 32 0.01 0.003 3.33 33 0.016 0.006 2.67 36 0.071 0.024 2.96 37 0.114 0.124 0.92 38 0.179 0.067 2.67 39 0.294 0.083 3.54 43 1.994 0.614 3.25 44 3.213 0.939 3.42 [...]... nghiệm bài toán nhân hai ma trận vuông bằng thuật toán Strassen 3 Kết luận Tiểu luận đã tập trung vào giới thiệu khuôn khổ Java Fork/ Join cùng một số ví dụ minh họa cách áp dụng khuôn khổ này cho một số bài toán cụ thể, như sau: - Giới thiệu nguồn gốc hình thành, mục đích của khuôn khổ Java Fork/ Join Mô tả ý tưởng thiết kế và cách thức vận hành khuôn khổ một cách tổng quan 17 Tiểu luận môn học: Điện toán. .. 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 12 Tiểu luận môn học: Điện toán lưới và đám mây { 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[][]... sumMatrix(b11, b12, n/2), n/2); a12 = extractMatrix(a, n, 1, 2); t4 = new StrassenForkJoin(sumMatrix(a11, a12, n/2), b22, n/2); 15 Tiểu luận môn học: Điện toán lưới và đám mây t5 = new StrassenForkJoin(a11, subMatrix(b12, b22, n/2), n/2); t6 = new StrassenForkJoin(a22, subMatrix(b21, b11, n/2), n/2); t7 = new StrassenForkJoin(sumMatrix(a21, a22, n/2), b11, n/2); invokeAll(t1, t2, t3, t4, t5, t6, t7);... toán lưới và đám mây - Trình bày ví dụ áp dụng bằng mã cụ thể để có thể kiểm chứng khi cần thiết Đưa ra một bảng so sánh hiệu năng thời gian chạy cho cả hai phiên bản tuần tự, song song Bên cạnh đó tiểu luận cũng có một số hạn chế như: chưa đưa ra một hình ảnh trực quan về kiến trúc của khuôn khổ Java Fork/ Join, chưa thảo luận sâu về những vấn đề kinh điển trong mô hình lập trình song song chia sẻ bộ... 10.629 3.013 10.74 3.322 10.638 3.106 song hóa với Fork/ Join Speedup nhanh hơn 3.15 với phiên 3.34 3.76 3.60 3.10 3.25 3.43 3.53 3.23 3.42 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 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... Thuần(Chủ biên), Hồ Cẩm Hà, Trần Thiên Thành(2008), Cấu trúc dữ liệu, Phân tích thuật toán và Phát triển phần mềm, Nhà xuất bản Giáo Dục 3 http://www.deftitlenil.com/2011/04/blog-post_05.html 18 Tiểu luận môn học: Điện toán lưới và đám mây 4 The Java http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html 19 Tutorials, ... 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, 4, 8…2048 Với kích thước từ 2 – 64 phiên bản song song chạy chậm hơn phiên bản tuần 16 Tiểu luận môn học: Điện toán lưới và đám mây tự Nhưng từ kích thước 128 trở về sau phiên bản song song chạy nhanh hơn gấp ba lần phiên bản tuần tự N 2 4 8 16 32 64 128 512 1024 2048 Serial execution time 0.001 0.000 0.000 0.001.. .Tiểu luận môn học: Điện toán lưới và đám mây 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; }... hóa( synchronization), thu gom rác(Garbage collection), vai trò của hàng đợi task trong việc điều phối các task cho các worker thread cũng như chưa chứng minh rằng có phải: lấy task để thực thi bằng quy tắc LIFO và trộm task bằng quy tắc FIFO là thiết kế tối ưu các cho các khuôn khổ fork/ join hay không Vì vậy hướng phát triển của tiểu luận là: - Mô tả kiến trúc và các thiết kế cơ bản của khuôn khổ bằng. .. Mô tả kiến trúc và các thiết kế cơ bản của khuôn khổ bằng biểu đồ UML Thảo luận các về cơ chế đồng bộ hóa (synchronization), thu gom rác(Garbage - collection) trong quá trình thực hiện song song Chứng minh rằng: lấy task để thực thi bằng quy tắc LIFO và trộm task bằng quy - tắc FIFO là thiết kế tối ưu các cho các khuôn khổ fork/ join Đánh giá hiệu năng so với các khuôn khổ khác có cùng tính năng 4 Tài . Tiểu luận môn học: Điện toán lưới và đám mây ĐẠ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. hạn) 7 Tiểu luận môn học: Điện toán lưới và đám mây 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. 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 1 Tiểu luận môn học: Điện toán lưới và đám mây Mục

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

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN

w