bỘ giÁo dỤc vÀ ĐÀo tẠo i hỌc lẠc...
TRANSCRIPT
BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƯỜNG ĐẠI HỌC LẠC HỒNG
* * *
Đặng Như Toàn
Song song hoá thuật toán tìm đường đi ngắn nhất
trên nguồn dữ liệu lớn dùng MPI
Luận văn Thạc sỹ Công nghệ thông tin
Đồng Nai - năm 2011
BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƯỜNG ĐẠI HỌC LẠC HỒNG
* * *
Đặng Như Toàn
Song song hoá thuật toán tìm đường đi ngắn nhất
trên nguồn dữ liệu lớn dùng MPI
Chuyên ngành: Công nghệ thông tin
Mã số: 604805
Luận văn Thạc sỹ Công nghệ thông tin
Người hướng dẫn khoa học
PGS.TS Trần Văn Lăng
Đồng Nai - năm 2011
LỜI CẢM ƠN
Được sự định hướng của thầy PGS. TS Trần Văn Lăng, em đã lựa chọn đề tài
“Song song hoá thuật toán tìm kiếm đường đi ngắn nhất với MPI”.
Được sự giúp đỡ và hướng dẫn tận tình của thầy PGS. TS Trần Văn Lăng và một
số đồng nghiệp, đến nay em đã hoàn thành luận văn của mình. Mặc dù đã cố
gắng, nhưng do thời gian có hạn và hạn chế của bản thân nên không tránh khỏi
có những thiếu sót. Em rất mong nhận được ý kiến đóng góp của các Thầy Cô và
các bạn đồng nghiệp để luận văn được hoàn thiện hơn.
Tác giả
Đặng Như Toàn
MỤC LỤC
Trang
LỜI CẢM ƠN ....................................................................................................... iii
MỤC LỤC ............................................................................................................. iv
Danh mục các thuật ngữ ....................................................................................... vii
Danh mục các hình vẽ, bảng biểu ....................................................................... viii
MỞ ĐẦU ................................................................................................................ 1
1. Đặt vấn đề ........................................................................................................ 1
2. Mục đích của luận văn..................................................................................... 1
3. Nội dung của luận văn ..................................................................................... 1
4. Phương pháp nghiên cứu ................................................................................. 2
CHƯƠNG 1 - MỘT SỐ KỸ THUẬT TÌM KIẾM ĐƯỜNG ĐI NGẮN NHẤT .. 3
1.1. Bài toán tìm kiếm đường đi ngắn nhất ......................................................... 3
1.2. Các thuật toán ............................................................................................... 4
1.2.1. Thuật toán Dijkstra ................................................................................. 4
1.2.2. Thuật toán A star .................................................................................... 6
1.2.3. Thuật toán di truyền ............................................................................... 9
CHƯƠNG 2 - LẬP TRÌNH SONG SONG VỚI MPI ......................................... 16
2.1. Tổng quan về lập trình song song với MPI ................................................ 16
2.1.1. Giới thiệu .............................................................................................. 16
2.1.2 Một số đặc điểm của lập trình MPI ....................................................... 17
2.2. Lập trình song song với MPI ...................................................................... 19
2.2.1. Giới thiệu .............................................................................................. 19
2.2.2. Một số vấn đề về hiệu năng .................................................................. 21
2.2.2.1 Năng lực tính toán ........................................................................... 21
2.2.2.2 Cân bằng tải ..................................................................................... 23
2.2.2.3 Sự bế tắc .......................................................................................... 25
CHƯƠNG 3 - MPI TRONG THUẬT TOÁN DIJKSTRA CHO BÀI TOÁN TÌM
KIẾM ĐƯỜNG ĐI NGẮN NHẤT ...................................................................... 27
3.1. Yêu cầu đặt ra cho bài toán tìm kiếm đường đi ngắn nhất theo giải thuật
Dijksta ................................................................................................................ 27
3.2. Xây dựng hàm tìm kiếm đường đi ngắn nhất ............................................. 27
3.2.1 Xây dựng thuật toán Dijkstra tuần tự cho bài toán ............................... 27
3.2.2 Thực hiện song song hoá ....................................................................... 28
3.2.3 Thuật toán song song ............................................................................. 29
3.2.4 Lựa chọn hàm MPI cho thuật toán song song ....................................... 30
3.2.5 Công thức song song ............................................................................. 35
3.3. Chi phí thời gian ......................................................................................... 38
CHƯƠNG 4 - KẾT QUẢ THỬ NGHIỆM .......................................................... 39
4.1. Các kết quả thử nghiệm .............................................................................. 39
4.1.1. Kết quả thử nghiệm giải thuật Dijkstra cổ điển ................................... 39
4.1.2. Kết quả thử nghiệm tìm kiếm bằng giải thuật Dijkstra song song ....... 40
4.2. Đánh giá kết quả ......................................................................................... 41
KẾT LUẬN .......................................................................................................... 44
TÀI LIỆU THAM KHẢO .................................................................................... 45
Danh mục các thuật ngữ
LIS – Language Independent Specifications
MIMD – Multiple Instruction Multiple Data
MPI – Message Passing Interface
OSI – Open Systems Interconnection
PVM – Parallel Vitual Machine
TCP – Transmission Control Protocol
TTDT – Thuật toán di truyền
Danh mục các hình vẽ, bảng biểu
Hình 1.1 – Kỹ thuật quay bánh xe
Hình 2.1 – Khả năng tăng tốc độ tính toán, trường hợp lý tưởng
Hình 2.2 – Khả năng tăng tốc độ tính toán, trường hợp thực tế
Hình 3.1 – Sơ đồ khối thuật toán Dijkstra song song
Bảng 4.1 – Thời gian thực hiện thuật toán Dijkstra cổ điển
Bảng 4.2 – Thời gian thực hiện thuật toán Dijkstra song song
Bảng 4.3: Thời gian thực hiện thuật toán Dijkstra song song với nhiều tiến trình
Hình 4.4: So sánh kết quả thử nghiệm thuật toán Dijksta
Hình 4.5: So sánh kết quả thử nghiệm thuật toán Dijksta với nhiều tiến trình
1
MỞ ĐẦU
1. Đặt vấn đề
Tim kiếm đường đi ngắn nhất là một bài toán kinh điển đã được nghiên cứu rất
nhiều và ứng dụng trong những hệ thống chuyên biệt. Rất nhiều nghiên cứu đã
cải tiến những thuật toán và tối ưu thuật toán về không gian tìm kiếm, thời gian
tìm kiếm.
Tuy nhiên, với sự bùng nổ thông tin và sự phát triển của công nghệ thông tin,
những thuật toán tìm kiếm đường đi ngắn nhất kinh điển không thể đáp ứng
được thời gian tìm kiếm tốt nhất trên lượng dữ liệu lớn.
Bài toán đặt ra là làm thế nào để giải quyết vấn đề tìm kiếm đường đi ngắn nhất
với nguồn dữ liệu lớn và phân tán, đáp ứng được mục tiêu rút ngắn thời gian tìm
kiếm.
2. Mục đích của luận văn
Nghiên cứu và song song hoá thuật toán Dijkstra cho bài toán tìm đường đi ngắn
nhất trên nguồn dữ liệu lớn và phân tán; từ đó nâng cao hiệu quả của việc xử lý
dữ liệu.
3. Nội dung của luận văn
Trong luận văn này gồm có 3 nội dung:
- Nội dung 1: Nghiên cứu về bài toán tìm kiếm đường đi ngắn nhất. Đánh giá
ưu điểm, nhược điểm của từng thuật toán.
2
- Nội dung 2: Cải tiến thuật toán Dijkstra cho bài toán tìm kiếm đường đi
ngắn nhất bằng cách song song hóa thuật toán để tối ưu về thời gian tìm kiếm
trên nguồn dữ liệu lớn.
- Nội dung 3: Tiến hành thử nghiệm, đánh giá thuật toán cải tiến.
4. Phương pháp nghiên cứu
Để thực hiện những nội dung đã nêu ở trên, tác giả đã sử dụng một số phương
pháp cho từng nội dung như sau:
- Nội dung 1: sử dụng phương pháp phân tích, so sánh và đánh giá các thuật
toán tìm kiếm đường đi ngắn nhất.
- Nội dung 2: sử dụng phương pháp phân tích khả năng song song hóa thuật
toán Dijkstra.
- Nội dung 3: sử dụng phương pháp đối sánh để đánh giá kết quả thử nghiệm
của thuật toán đã cải tiến.
3
CHƯƠNG 1 - MỘT SỐ KỸ THUẬT TÌM KIẾM ĐƯỜNG ĐI NGẮN
NHẤT
1.1. Bài toán tìm kiếm đường đi ngắn nhất
Trong lý thuyết đồ thị, bài toán đường đi ngắn nhất nguồn đơn là bài toán tìm
một đường đi giữa hai đỉnh sao cho tổng các trọng số của các cạnh tạo nên
đường đi đó là nhỏ nhất.
Định nghĩa một cách hình thức, cho trước một đồ thị có trọng số (nghĩa là một
tập đỉnh V, một tập cạnh E, và một hàm trong số có giá trị thực f: E → R), cho
trước một đỉnh v thuộc V, tìm một đường đi P từ v tới mỗi đỉnh v' thuộc V sao
cho: Pp
pf )( là nhỏ nhất trong tất cả các đường nối từ v tới v'.
Các thuật toán quan trọng nhất giải quyết bài toán này là:
- Thuật toán Dijkstra: giải bài toán nguồn đơn nếu tất cả các trọng số đều
không âm. Thuật toán này có thể tính toán tất cả các đường đi ngắn nhất từ một
đỉnh xuất phát cho trước s tới mọi đỉnh khác mà không làm tăng thời gian chạy.
- Thuật toán Bellman-Ford: giải bài toán nguồn đơn trong trường hợp trọng
số có thể có giá trị âm.
- Thuật toán tìm kiếm A*: giải bài toán nguồn đơn sử dụng heuristics để tăng
tốc độ tìm kiếm.
- Thuật toán Floyd-Warshall: giải bài toán đường đi ngắn nhất cho mọi cặp
đỉnh.
4
- Thuật toán Johnson: giải bài toán đường đi ngắn nhất cho mọi cặp đỉnh, có
thể nhanh hơn thuật toán Floyd-Warshall trên các đồ thị thưa.
Lý thuyết nhiễu (Perturbation theory): tìm đường đi ngắn nhất địa phương (trong
trường hợp xấu nhất).
1.2. Các thuật toán
1.2.1. Thuật toán Dijkstra
Thuật toán Dijkstra [2], mang tên của nhà khoa học máy tính người Hà
Lan Edsger Dijkstra, là một thuật toán giải quyết bài toán đường đi ngắn
nhất nguồn đơn trong một đồ thị có hướng không có cạnh mang trọng số âm.
Bài toán: Cho đơn đồ thị liên thông, có trọng số G=(V,E). Tìm khoảng cách
d(u0,v) từ một đỉnh u0 cho trước đến một đỉnh v bất kỳ của G và tìm đường đi
ngắn nhất từ u0 đến v.
Phương pháp của thuật toán Dijkstra là: xác định tuần tự đỉnh có khoảng cách
đến u0 từ nhỏ đến lớn.
Trước tiên, đỉnh có khoảng cách đến a nhỏ nhất chính là a, với d(u0,u0)=0. Trong
các đỉnh v u0, tìm đỉnh có khoảng cách k1 đến u0 là nhỏ nhất. Đỉnh này phải là
một trong các đỉnh kề với u0. Giả sử đó là u1:
d(u0,u1) = k1.
Trong các đỉnh v u0 và v u1, tìm đỉnh có khoảng cách k2 đến u0 là nhỏ nhất.
Đỉnh này phải là một trong các đỉnh kề với u0 hoặc với u1. Giả sử đó là u2:
d(u0,u2) = k2.
5
Tiếp tục như trên, cho đến bao giờ tìm được khoảng cách từ u0 đến mọi đỉnh v
của G. Nếu V={u0, u1, ..., un} thì:
0 = d(u0,u0) < d(u0,u1) < d(u0,u2) < ... < d(u0,un).
Thuật toán Dijkstra:
Procedure Dijkstra (G=(V,E) là đơn đồ thị liên thông, có trọng số với trọng số
dương)
{G có các đỉnh a=u0, u1, ..., un=z và trọng số m(ui,uj), với
m(ui,uj) =
nếu (ui,uj) không là một cạnh trong G}
for i:= 1 to n
L(ui):=
L(a):= 0
S:= V \ {a}
u:= a
while S
begin
for tất cả các đỉnh v thuộc S
if L(u) +m(u,v) < L(v) then L(v) := L(u)+m(u,v)
u:= đỉnh thuộc S có nhãn L(u) nhỏ nhất
{L(u): độ dài đường đi ngắn nhất từ a
đến u}
6
S:= S \ {u}
end
End Pro
Độ phức tạp của thuật toán Dijkstra: Thuật toán dùng không quá n1 bước lặp.
Trong mỗi bước lặp, dùng không hơn 2(n1) phép cộng và phép so sánh để sửa
đổi nhãn của các đỉnh. Ngoài ra, một đỉnh thuộc Sk có nhãn nhỏ nhất nhờ không
quá n1 phép so sánh. Do đó thuật toán có độ phức tạp O(n2).
1.2.2. Thuật toán A star
Thuật toán A* [1] được mô tả lần đầu vào năm 1968 bởi Peter Hart, Nils
Nilsson, và Bertram Raphael. Trong bài báo của họ, thuật toán được gọi là thuật
toán A; khi sử dụng thuật toán này với một đánh giá heuristic thích hợp sẽ thu
được hoạt động tối ưu, do đó mà có tên A*.
Thuật toán này tìm một đường đi từ một nút khởi đầu tới một nút đích cho trước
(hoặc tới một nút thỏa mãn một điều kiện đích). Thuật toán này sử dụng một
"đánh giá heuristic" để xếp loại từng nút theo ước lượng về tuyến đường tốt nhất
đi qua nút đó. Thuật toán này duyệt các nút theo thứ tự của đánh giá heuristic
này. Do đó, thuật toán A* là một ví dụ của tìm kiếm theo lựa chọn tốt nhất (best-
first search).
Bài toán: Giả sử u là một trạng thái đạt tới (có đường đi từ trạng thái ban đầu u0
tới u). Xác định hai hàm đánh giá sau:
- g(u) là đánh giá độ dài đường đi ngắn nhất từ u0 tới u (Đường đi từ u0 tới
trạng thái u không phải là trạng thái đích được gọi là đường đi một phần, để phân
biệt với đường đi đầy đủ, là đường đi từ u0 tới trạng thái đích).
7
- h(u) là đánh giá độ dài đường đi ngắn nhất từ u tới trạng thái đích.
Hàm h(u) được gọi là chấp nhận được (hoặc đánh giá thấp) nếu với mọi trạng
thái u, h(u) độ dài đường đi ngắn nhất thực tế từ u tới trạng thái đích. Chẳng
hạn trong bài toán tìm đường đi ngắn nhất trên bản đồ giao thông, có thể xác
định h(u) là độ dài đường chim bay từ u tới đích.
Có thể sử dụng kỹ thuật tìm kiếm leo đồi với hàm đánh giá h(u). Tất nhiên
phương pháp này chỉ cho phép tìm được đường đi tương đối tốt, chưa chắc đã là
đường đi tối ưu.
Ngoài ra, cũng có thể sử dụng kỹ thuật tìm kiếm tốt nhất đầu tiên với hàm đánh
giá g(u). Phương pháp này sẽ tìm ra đường đi ngắn nhất, tuy nhiên nó có thể kém
hiệu quả.
Để tăng hiệu quả tìm kiếm, có thể sử dụng hàm đánh giá mới:
f(u) = g(u) + h(u)
Tức là, f(u) là đánh giá độ dài đường đi ngắn nhất qua u từ trạng thái ban đầu tới
trạng thái kết thúc.
Thuật toán A* là thuật toán sử dụng kỹ thuật tìm kiếm tốt nhất đầu tiên với hàm
đánh giá f(u).
Thuật toán A*:
begin
1. Khởi tạo danh sách L chỉ chứa trạng thái ban đầu;
2. loop do
2.1 if L rỗng then
8
{thông báo thất bại; stop};
2.2 Loại trạng thái u ở đầu danh sách L;
2.3 if u là trạng thái đích then
{thông báo thành công; stop}
2.4 for mỗi trạng thái v kề u do
{g(v) g(u) + k(u,v);
f(v) g(v) + h(v);
Đặt v vào danh sách L;}
2.5 Sắp xếp L theo thứ tự tăng dần của hàm f sao cho
trạng thái có giá trị của hàm f nhỏ nhất
ở đầu danh sách;
end;
Độ phức tạp của thuật toán A*: Độ phức tạp thời gian của A* phụ thuộc vào
đánh giá heuristic. Trong trường hợp xấu nhất, số nút được mở rộng theo hàm
mũ của độ dài lời giải, nhưng nó sẽ là hàm đa thức khi hàm heuristic hthỏa mãn
điều kiện sau:
|h(x) – h*(x)| ≤ O(log h*(x))
Trong đó h * là heuristic tối ưu, nghĩa là hàm cho kết quả là chi phí chính xác để
đi từ x tới đích. Nói cách khác, sai số của h không nên tăng nhanh
hơn lôgarit của "heuristic hoàn hảo" h * - hàm trả về khoảng cách thực từ x tới
đích.
9
Vấn đề sử dụng bộ nhớ của A* còn rắc rối hơn độ phức tạp thời gian. Trong
trường hợp xấu nhất, A* phải ghi nhớ số lượng nút tăng theo hàm mũ.
1.2.3. Thuật toán di truyền
Thuật toán di truyền (TTDT) là thuật toán bắt chước sự chọn lọc tự nhiên và di
truyền. Trong tự nhiên, các cá thể khỏe, có khả năng thích nghi tốt với môi
trường sẽ được tái sinh và nhân bản ở các thế hệ sau. Mỗi cá thể có cấu trúc gien
đặc trưng cho phẩm chất của cá thể đó. Trong quá trình sinh sản, các cá thể con
có thể thừa hưởng các phẩm chất của cả cha và mẹ, cấu trúc gien của nó mang
một phần cấu trúc gien của cha và mẹ. Ngoài ra, trong quá trình tiến hóa, có thể
xảy ra hiện tượng đột biến, cấu trúc gien của cá thể con có thể chứa các gien mà
cả cha và mẹ đều không có.
Trong TTDT, mỗi cá thể được mã hóa bởi một cấu trúc dữ liệu mô tả cấu trúc
gien của cá thể đó, ta sẽ gọi nó là nhiễm sắc thể (chroniosome). Mỗi nhiễm sắc
thể được tạo thành từ các đơn vị được gọi là gien. Chẳng hạn, trong các TTDT
cổ điển, các nhiễm sắc thể là các chuỗi nhị phân, tức là mỗi cá thể được biểu
diễn bởi một chuỗi nhị phân.
TTDT sẽ làm việc trên các quần thể gồm nhiều cá thể. Một quần thể ứng với một
giai đoạn phát triển sẽ được gọi là một thế hệ. Từ thế hệ ban đầu được tạo ra,
TTDT bắt chước chọn lọc tự nhiên và di truyền để biến đổi các thế hệ. TTDT sử
dụng các toán tử cơ bản sau đây để biến đổi các thế hệ:
- Toán tử tái sinh (reproduction) (còn được gọi là toán tử chọn lọc
(selection)): Các cá thể tốt được chọn lọc để đưa vào thế hệ sau. Sự lựa chọn này
được thực hiện dựa vào độ thích nghi với môi trường của mỗi cá thể. Ta sẽ gọi
hàm ứng mỗi cá thể với độ thích nghi của nó là hàm thích nghi (fitness function).
10
- Toán tử lai ghép (crossover): Hai cá thể cha và mẹ trao đổi các gien để tạo
ra hai cá thể con.
- Toán tử đột biến (mutation): Một cá thể thay đổi một số gien để tạo thành
cá thể mới.
Tất cả các toán tử trên khi thực hiện đều mang tính ngẫu nhiên. Cấu trúc cơ bản
của TTDT là như sau:
procedure Genetic_Algorithm;
begin
t 0;
Khởi tạo thế hệ ban đầu P(t);
Đánh giá P(t) (theo hàm thích nghi);
repeat
t t + 1;
Sinh ra thế hệ mới P(t) từ P(t-1) bởi
Chọn lọc
Lai ghép
Đột biến;
Đánh giá P(t);
until điều kiện kết thúc được thỏa mãn;
end;
11
Trong thủ tục trên, điều kiện kết thúc vòng lặp có thể là một số thế hệ đủ lớn nào
đó, hoặc độ thích nghi của các cá thể tốt nhất trong các thế hệ kế tiếp nhau khác
nhau không đáng kể. Khi thuật toán dừng, cá thể tốt nhất trong thế hệ cuối cùng
được chọn làm nghiệm cần tìm.
Xét chi tiết hơn toán tử chọn lọc và các toán tử di truyền (lai ghép, đột biến)
trong các TTDT cổ điển:
Chọn lọc:
Việc chọn lọc các cá thể từ một quần thể dựa trên độ thích nghi của mỗi cá thể.
Các cá thể có độ thích nghi cao có nhiều khả năng được chọn. Cần nhấn mạnh
rằng, hàm thích nghi chỉ cần là một hàm thực dương, nó có thể không tuyến tính,
không liên tục, không khả vi. Quá trình chọn lọc được thực hiện theo kỹ thuật
quay bánh xe.
Giả sử thế hệ hiện thời P(t) gồm có n cá thể {x1,..,xn}. Số n được gọi là cỡ của
quần thể. Với mỗi cá thể xi, tính độ thích nghi của nó f(xi). Tính tổng các độ
thích nghi của tất cả các cá thể trong quần thể:
n
1i
f(xi)F
Mỗi lần chọn lọc, thực hiện hai bước sau:
- Sinh ra một số thực ngẫu nhiên q trong khoảng (0, F);
- xk là cá thể được chọn, nếu k là số nhỏ nhất sao cho
k
i
xif1
4)(
12
Việc chọn lọc theo hai bước trên có thể minh họa như sau: Có một bánh xe được
chia thành n phần, mỗi phần ứng với độ thích nghi của một cá thể (hình 1). Một
mũi tên chỉ vào bánh xe. Quay bánh xe, khi bánh xe dừng, mũi tên chỉ vào phần
nào, cá thể ứng với phần đó được chọn.
Hình 1.1: Kỹ thuật quay bánh xe
Rõ ràng là với cách chọn này, các cá thể có thể có độ thích nghi càng cao càng
có khả năng được chọn. Các cá thể có độ thích nghi cao có thể có một hay nhiều
bản sao, các cá thể có độ thích nghi thấp có thể không có mặt ở thế hệ sau (nó bị
chết đi).
Lai ghép:
Trên cá thể được chọn lọc, tíến hành toán tử lai ghép. Đầu tiên cần đưa ra xác
suất lai ghép pc. xác suất này cho hy vọng có pc.n cá thể được lai ghép (n là cỡ
của quần thể).
Với mỗi cá thể ta thực hiện hai bước sau:
- Sinh ra số thực ngẫu nhiên r trong đoạn [0, 1];
- Nếu r < pc thì cá thể đó được chọn để lai ghép
Từ các cá thể được chọn để lai ghép, người ta cặp đôi chúng một cách ngẫu
nhiên. Trong trường hợp các nhiễm sắc thể là các chuỗi nhị phân có độ dài cố
định m, ta có thể thực hiện lai ghép như sau: Với mỗi cặp, sinh ra một số nguyên
13
ngẫu nhiên p trên đoạn [0, m -1], p là vị trí điểm ghép. Cặp gồm hai nhiễm sắc
thể
a = (a1 , ... , ap , ap+1 , ... , am)
a = (b1 , ... , bp , bp+1 , ... , bm)
được thay bởi hai con là:
a' = (a1 , ... , ap , bp+1 , ... , bm)
b' = (b1 , ... , bp , ap+1 , ... , am)
Đột biến:
Thực hiện toán tử đột biến trên các cá thể có được sau quá trình lai ghép. Đột
biến là thay đổi trạng thái một số gien nào đó trong nhiễm sắc thể. Mỗi gien chịu
đột biến với xác suất pm. Xác suất đột biến pm do ta xác định và là xác suất thấp.
Sau đây là toán tử đột biến trên các nhiễm sắc thể chuỗi nhị phân.
Với mỗi vị trí i trong nhiễm sắc thể:
a = (a1 , ... , ai , ... , am)
Sinh ra một số thực nghiệm ngẫu nhiên pi trong [0,1]. Qua đột biến a được biến
thành a’ như sau:
a' = (a'1 , ... , a'i , ... , a'm)
Trong đó:
a'i = ai nếu pi pm
1 - ai nếu pi < pm
14
Sau quá trình chọn lọc, lai ghép, đột biến, một thế hệ mới được sinh ra. Công
việc còn lại của thuật toán di truyền bây giờ chỉ là lặp lại các bước trên.
Thuật toán di truyền khác với các thuật toán tối ưu khác ở các điểm sau:
- TTDT chỉ sử dụng hàm thích nghi để hướng dẫn sự tìm kiếm, hàm thích
nghi chỉ cần là hàm thực dương. Ngoài ra, nó không đòi hỏi không gian tìm kiếm
phải có cấu trúc nào cả.
- TTDT làm việc trên các nhiễm sắc thể là mã của các cá thể cần tìm.
- TTDT tìm kiếm từ một quần thể gồm nhiều cá thể.
- Các toán tử trong TTDT đều mang tính ngẫu nhiên.
Để giải quyết một vấn đề bằng TTDT, cần thực hiện các bước sau đây:
- Trước hết cần mã hóa các đối tượng cần tìm bởi một cấu trúc dữ liệu nào
đó.
- Thiết kế hàm thích nghi. Trong các bài toán tối ưu, hàm thích nghi được xác
định dựa vào hàm mục tiêu.
- Trên cơ sở cấu trúc của nhiễm sắc thể, thiết kế các toán tử di truyền (lai
ghép, đột biến) cho phù hợp với các vấn đề cần giải quyết.
- Xác định cỡ của quần thể và khởi tạo quần thể ban đầu.
- Xác định xác suất lai ghép pc và xác suất đột biến. Xác suất đột biến cần là
xác suất thấp. Người ta (Goldberg, 1989) khuyên rằng nên chọn xác suất lai ghép
là 0,6 và xác suất đột biến là 0,03. Tuy nhiên cần qua thử nghiệm để tìm ra các
xác suất thích hợp cho vấn đề cần giải quyết.
15
Nói chung thuật ngữ TTDT là để chỉ TTDT cổ điển, khi mà cấu trúc của các
nhiễm sắc thể là các chuỗi nhị phân với các toán tử di truyền đã được mô tả ở
trên. Song trong nhiều vấn đề thực tế, thuận tiện hơn, có thể biểu diễn nhiễm sắc
thể bởi các cấu trúc khác, chẳng hạn vectơ thực, mảng hai chiều, cây... Tương
ứng với cấu trúc của nhiễm sắc thể, có thể có nhiều cách xác định các toán tử di
truyền. Quá trình sinh ra thế hệ mới P(t) từ thế hệ cũ P(t - 1) cũng có nhiều cách
chọn lựa. Người ta gọi chung các thuật toán này là thuật toán tiến hóa
(evolutionary algorithms) hoặc chương trình tiến hóa (evolution program).
16
CHƯƠNG 2 - LẬP TRÌNH SONG SONG VỚI MPI
2.1. Tổng quan về lập trình song song với MPI
2.1.1. Giới thiệu
Message Passing Interface – MPI là một chuẩn mới được sử dụng rộng rãi nhất.
Nó không phải là một ngôn ngữ lập trình mới, thay vào đó nó là một thư viện
của chương trình con mà có thể được gọi từ chương trình C và Fortran 77.
MPI được phát triển bởi một diễn đàn mở quốc tế, bao gồm các đại diện từ
ngành công nghiệp, các học viện và phòng thí nghiệm của chính phủ. Nó đã
nhanh chóng được chấp nhận rộng rãi bởi được thiết kế cẩn thận cho phép hiệu
suất tối đa trên một loạt các hệ thống, và nó dựa trên truyền thông điệp, một
trong những mô hình mạnh mẽ nhất và được sử dụng rộng rãi cho lập trình các
hệ thống song song.
Những nỗ lực cho MPI bắt đầu vào mùa hè năm 1991, khi một nhóm nhỏ các
nhà nghiên cứu bắt đầu thảo luận tại một nơi hẻo lánh trên núi ở Úc.
Nội dung đó lại được thảo luận tại hội thảo “tiêu chuẩn cho truyền thông điệp
trong một môi trường bộ nhớ phân tán” (Standards for Message Passing in a
Distributed Memory environment) tổ chức vào ngày 29 – 30 tháng 4 năm 1992
tại Williamsburg, Virginia. Tại hội thảo này, các tính năng cơ bản cần thiết cho
một MPI chuẩn đã được thảo luận, mà một nhóm cộng tác đã được thành lập để
tiếp tục quá trình tiêu chuẩn hoá. Jack Dongarra, Rolf Hempel Hempel, Tony
Hey và David W.Walker đưa ra một bản dự thảo sơ bộ được biết đến như MPI-1
trong tháng 11 năm 1992.
17
Trong tháng 11 năm 1992, một cuộc họp của nhóm cộng tác MPI đã được tổ
chức tại Minneapolis, mà tại đó hội thảo quyết định đặt các quá trình tiêu chuẩn
hoá trên một cơ sở chính thức hơn. Nhóm cộng tác MPI đã gặp nhau 6 tuần một
lần trong suốt 9 tháng đầu của năm 1993. Bản dự thảo chuẩn MPI đã được trình
bày tại hội nghị Siêu máy tính năm 93 trong tháng 11 năm 1993.
Sau một thời gian nhận những ý kiến đóng góp từ cộng đồng, một số kết quả
được thay đổi trong MPI, phiên bản 1.0 của MPI được phát hành vào tháng 6
năm 1994. Thông qua những cuộc gặp gỡ và thư điện tử, các nhà nghiên cứu đã
thảo luận với nhau thành lập diễn đàn MPI, trong đó tất cả các thành viên của
cộng đồng điện toán hiệu suất cao đều có thể đăng ký làm thành viên của diễn
đàn.
MPI đã thu hút sự tham gia khoảng 80 người từ 40 tổ chức, chủ yếu là ở Mỹ và
Châu Âu. Hầu hết các nhà cung cấp chính của máy tính đều được tham gia vào
MPI cùng với các nhà nghiên cứu từ các trường đại học, phòng thí nghiệm của
chính phủ và ngành công nghiệp.
2.1.2 Một số đặc điểm của lập trình MPI
MPI là một giao thức truyền thông độc lập với ngôn ngữ dùng để lập trình máy
tính song song. MPI hỗ trợ cả giao tiếp điểm – điểm và giao tiếp tập thể. Mục
tiêu của MPI là hiệu suất, khả năng mở rộng và khả năng di dộng cao.
MPI thường xuyên chạy trên các máy tính chia sẻ bộ nhớ.
Mặc dù MPI thuộc về lớp thứ 5 và lớp cao hơn của mô hình OSI, nhưng những
triển khai có thể bao gồm hầu hết các lớp, với socket và TCP (Transmission
Control Protocol) được dùng trong tần vận chuyển.
18
Hầu hết các triển khai MPI bao gồm một thiết lập định tuyến riêng có thể được
gọi trực tiếp từ C, C++, Fortran hay bất kỳ ngôn ngữ nào có giao diện với các
thư viện, bao gồm C#, Java hoặc Python. Những ưu điểm ucar MPI vượt qua
những thư viện truyền thông điệp cũ là tính di động (MPI có thể được triển khai
cho hầu hết các kiến trúc bộ nhớ phân tán) và tốc độ (MPI thực hiện nguyên tắc
tối ưu hoá cho phần cứ mà nó chạy).
MPI sử dụng LIS (Language Independent Specifications) để gọi và ràng buộc
ngôn ngữ. Phiên bản đầu tiên được phát hành chỉ định ràng buộc ANSI C và
Fortran 77 cùng với LIS. Năm 2008, chuẩn MPI-1.3 chứa khoảng 128 chức
năng, đây cũng là phát hành cuối cùng của seri MPI-1 trong năm 2008.
Phiên bản MPI-2.2 bao gồm những tính năng nới như là I/O song song, quản lý
tiến trình động và điều hành bộ nhớ từ xa. LIS của MPI-2 thiết lập hơn 500 hàm
và cung cấp ràng buộc ngôn ngữ cho ANSI C, ANSI C++ và ANSI Fortran
(Fortran 90). Khả năng tương tác đối tượng cũng được thêm vào để cho phép lập
trình truyền thông điệp bằng ngôn ngữ hỗn hợp dễ dàng hơn.
MPI cung cấp mô hình liên kết ảo, đồng bộ hoá và chức năng liên lạc giữa một
tập hợp các tiến trình (đã được ánh xạ tới các nút/máy chủ/máy tính cụ thể) trong
một ngôn ngữ độc lập, với cú pháp ngôn ngữ đặc trưng (ràng buộc), cùng với
một vài tính năng ngôn ngữ đặc trưng. Những chương trình MPI luôn luôn làm
việc với các tiến trình, nhưng những lập trình viên thường xem các tiến trình như
là những bộ vi xử lý. Thông thường, để đạt hiệu suất tối đa, mỗi CPU (hoặc 1
nhân trong một máy tính đa nhân) sẽ được giao chỉ một tiến trình duy nhất.
Những chức năng thư viện MPI bao gồm (không giới hạn) những hoạt động
nhận/gửi loại điểm – điểm, lựa chọn giữa mô hình xử lý logic Cartesian hoặc mô
19
hình xử lý logic đồ thị tương đồng, trao đổi dữ liệu giữa những cặp tiến trình, kết
hợp các kết quả từng phần của tính toán (thu thập và giảm các hoạt động), đồng
bộ hoá các nút cũng như thu thập thông tin liên quan đế mạng như số lượng của
tiến trình trong phiên tính toán, nhận dang bộ vi xử lý hiện tại mà bộ vi xử lý
được ánh xạ, những tiến trình lân cận truy cập trong một mô hình liên kết logic.
2.2. Lập trình song song với MPI
2.2.1. Giới thiệu
Giao thức truyền thông điệp MPI là một thư viện các hàm và macro có thể được
gọi từ các chương trình sử dụng ngôn ngữ C, Fortran, và C++. Như tên gọi của
nó MPI được xây dựng nhằm sử dụng trong các chương trình để khai thác hệ
thống các bộ xử lý bằng cách truyền thông điệp.
* Mục tiêu thiết kế của MPI bao gồm:
- Thiết kế một giao diện lập trình ứng dụng. Mặc dù MPI gần đây được sử
dụng như một chương trình dịch và một thư viện ở thời gian chạy, nhưng thiết kế
của MPI chủ yếu phản ánh nhu cầu nhận thức của những người lập trình ứng
dụng.
- Cho phép truyền thông một cách hiệu quả: tránh việc sao chép dữ liệu từ bộ
nhớ sang bộ nhớ và cho phép gối chồng (overlap) giữa các tính toán và truyền
thông và offload để truyền thông đồng xử lý khi có thể.
- Cho phép thực thi trên một môi trường không đồng nhất.
- Có thể được gắn kết dễ dàng vào trong các chương trình ngôn ngữ C và
Fortran.
20
- Cung cấp một giao thức truyền thông tin cậy: người dùng không cần phải lo
lắng tới thất bại trong truyền thông. Các thất bại này được xử lý bởi các hệ thống
truyền thông cơ sở phía sau.
- Định nghĩa một giao thức không quá khác biệt so với các môi trường song
song hiện tại như PVM (Parallel Vitual Machine), NX, Express... và cung cấp
các mở rộng cho phép độ linh hoạt cao hơn.
- Định nghĩa một giao thức có thể được thực thi trên các môi trường
(flatform) của nhiều nhà cung cấp mà không cần thay đổi nào đáng kể trong
truyền thông cơ sở và phần mềm hệ thống.
- Ngữ nghĩa của giao thức là độc lập với ngôn ngữ.
- Giao thức được thiết kế cho phép sử dụng luồng một cách an toàn.
* Các tính năng chủ yếu của MPI [4]
- Một lượng lớn các hàm truyền thông điểm – điểm (phong phú hơn rất nhiều
so với các môi trường lập trình song song khác).
- Một lượng lớn các thủ tục truyền thông chọn lọc, được sử dụng để giao tiếp
giữa một nhóm các bộ xử lý trong hệ thống.
- Một ngữ cảnh truyền thông hỗ trợ cho việc thiết kế các thư viện phần mềm
song song.
- Có khả năng xác định các topology truyền thông.
- Có khả năng định nghĩa các kiểu dữ liệu mới để mô tả các thông báo dựa
trên các dữ liệu không liên tục.
* Các tiến trình
21
Một chương trình MPI bao gồm các bộ xử lý độc lập, thực thi các mã lệnh riêng
của chúng trong một mô hình MIMD (Multiple Instruction Multiple Data). Các
tập lệnh được thực thi bởi các bộ xử lý không nhất thiết phải giống nhau, việc
truyền thông giữa các bộ xử lý được thực hiện thông qua việc gọi các hàm truyền
thông của MPI.
MPI không định rõ kiểu thực thi cho mỗi bộ xử lý. Bộ xử lý A có thể chạy tuần
tự, hoặc có thể thực thi ở dạng đa luồng với các luồng được kích hoạt đồng thời.
Điều này thực hiện được do tính chất luồng an toàn (thread-safe) của MPI bằng
cách tránh sử dụng các trạng thái tuyệt đối.
* Ứng dụng MPI
Một ứng dụng MPI có thể được thực thi như là một tập các nhiệm vụ truyền
thông đồng thời. Một chương trình bao gồm các đoạn mã của người lập trình
được liên kết với các hàm thư viện được cung cấp bởi phần mềm MPI. Mỗi
nhiệm vụ được chỉ định một thứ hạng (rank) duy nhất trong khoảng 1-> n-1 với
các ứng dụng có n nhiệm vụ. Các hạng này được sử dụng để xác định các nhiệm
vụ MPI khác nhau trong việc gửi và nhận tin cũng như thực hiện các thao tác
truyền thông nói chung. Nhiệm vụ MPI có thể chạy trên cùng bộ xử lý hoặc các
bộ xử lý khác nhau một cách đồng thời. Lợi ích của các rank là làm cho thao tác
phối hợp độc lập với vị trí vật lý của các thành phần.
2.2.2. Một số vấn đề về hiệu năng
2.2.2.1 Năng lực tính toán
Việc song song hóa một chương trình nhằm làm cho chương trình đó chạy nhanh
hơn, tuy nhiên chương trình đó sẽ chạy nhanh hơn bao nhiêu lần? Định luật
Amdahl’s [3] cho phép ta xác định điều này. Giả sử xét về khía cạnh thời gian
22
chạy chương trình, một phần p của chương trình có thể song song hóa và phần 1-
p còn lại buộc phải chạy tuần tự. Trong trường hợp lý tưởng, nếu thực thi
chương trình sử dụng n bộ xử lý, thời gian chạy chương trình sẽ là 1-p + p/n của
thời gian chạy chương trình một cách tuần tự. Đây là hệ quả trực tiếp của định
luật Amdahl áp dụng cho trường hợp thực thi lý tưởng.
Ví dụ: nếu 80% chương trình có thể được song song hóa, và ta có 4 bộ xử lý,
thời gian chạy song song sẽ là: 1 - 0.8 + 0.8/4 = 0.4 tức là bằng 40% thời gian
chạy tuần tự.
Hình 2.1: khả năng tăng tốc độ tính toán, trường hợp lý tưởng
Đối với chương trình trên, thời gian chạy song song sẽ không thể nào nhỏ hơn
20% thời gian chạy tuần tự cho dù ta sử dụng số lượng vô cùng lớn các bộ xử lý.
Trên thực tế, khi chạy một chương trình song song, thường xuất hiện các chi phí
truyền thông và việc phân công công việc không cân bằng giữa các bộ xử lý. Do
đó thời gian chạy chương trình sẽ là:
23
Hinh 2.2: Khả năng tăng tốc độ tính toán, trường hợp thực tế.
Do vậy để tăng tốc độ của chương trình ta cần:
- Tăng tỉ lệ (thành phần) được song song hóa của chương trình.
- Phân công công việc một cách công bằng cho các bộ xử lý.
- Giảm tới mức tối thiểu thời gian truyền thông.
2.2.2.2 Cân bằng tải
Giả sử rằng nếu dữ liệu được phân tán trên các bộ nhớ địa phương của các bộ xử
lý trong hệ thống nhiều máy tính, khi đó khối lượng công việc của các bộ xử lý
cần phải được phân phối hợp lý trong suốt quá trình tính toán. Trong nhiều
trường hợp, giả sử này là đúng, tuy nhiên trong thực tế điều này không phải lúc
nào cũng thực hiện được. Giải pháp được đưa ra ở đây là cân bằng tải động
nhằm mục đích làm thay đổi sự phân phối khối lượng công viêc giữa các bộ xử
lý trong quá trình thực hiện tính toán.
24
Thông thường sau khi phân phối khối lượng công việc cho các bộ xử lý, quá
trình cân bằng tải động thực hiện bốn bước cơ bản sau:
- Giám sát hiệu năng của các bộ xử lý.
- Trao đổi thông tin trạng thái giữa các bộ xử lý.
- Tính toán và ra quyết định phân phối lại khối lượng công việc.
- Thực hiện việc chuyển đổi dữ liệu thực sự.
Để thực hiện được điều này, rất nhiều thuật toán đã được đề xuất. Người ta phân
lớp các thuật toán này theo các chiến lược: tập trung, phân tán hoàn toàn (fully
distributed) và phân tán một nửa (semi distributed).
a) Các thuật toán cân bằng tải tập trung
Các thuật toán này thường đưa ra quyết định có tính chất tổng thể trong việc
phân phối lại khối lượng công việc cho các bộ xử lý. Một vài thuật toán trong
lớp này sử dụng thông tin hệ thống có tính toàn cục để lưu trạng thái các máy
tính riêng lẻ. Thông tin này sẽ giúp thuật toán phân phối công việc một cách dễ
dàng. Tuy nhiên, khối lượng thông tin tăng theo tỉ lệ thuận với số lượng các bộ
xử lý, do đó nó đòi hỏi khối lượng lớn bộ nhớ trên một bộ xử lý để lưu thông tin
trạng thái. Vì vậy thuật toán thuộc lớp này không được tiếp cận một cách rộng
rãi.
b) Các thuật toán cân bằng tải phân tán hoàn toàn
Trong các thuật toán dạng này, mỗi bộ xử lý có một bản sao về thông tin trạng
thái của hệ thống. Các bộ xử lý trao đổi thông tin trạng thái với nhau và sử dụng
các thông tin này để làm thay đổi một cách cục bộ việc phân chia công việc. Tuy
25
nhiên các bộ xử lý chỉ có thông tin trạng thái cục bộ nên việc cân bằng tải không
tốt bằng các thuật toán cân bằng tải tập trung.
c) Các thuật toán cân bằng tải phân tán một nửa
Các thuật toán thuộc lớp này chia các bộ xử lý thành từng miền. Trong mỗi miền
sử dụng thuật toán cân bằng tải tập trung để phân phối công việc cho các bộ xử
lý thuộc miền đó.
2.2.2.3 Sự bế tắc
Các tiến trình xử lý bị rơi vào tình trạng bế tắc nếu mỗi tiến trình đó nắm giữ tài
nguyên mà một vài tiến trình khác đang yêu cầu để xử lý. Lý do tiềm ẩn của sự
bế tắc là do nhiều tiến trình cùng sử dụng nguồn tài nguyên chung mà không có
sự kiểm soát tốt.
Đối với các hệ thống đa máy tính, một trong những sự bế tắc phổ biến nhất là bế
tắc vùng đệm (buffer deadlock) xảy ra khi một tiến trình đợi một thông điệp mà
thông điệp này có thể không bao giờ nhận được do vùng đệm đã đầy.
Bốn điều kiện sau là nguyên nhân gây ra bế tắc:
1. Sự loại trừ lẫn nhau: mỗi tiến trình có sự độc quyền trong việc sử dụng
tài nguyên của nó.
2. Không có sự ưu tiên: Mỗi tiến trình không bao giờ giải phóng tài nguyên
mà nó đang chiếm giữ cho tới tận khi không còn sử dụng chúng nữa.
3. Sự chờ đợi tài nguyên: mỗi tiến trình đang chiếm giữ tài nguyên trong
khi lại chờ đợi các tiến trình khác giải phóng chúng.
4. Sự chờ đợi giữa các tiến trình: tiến trình chờ đợi tài nguyên mà tiến trình
kế tiếp đang chiếm giữ mà tài nguyên đó không được giải phóng.
26
* Một số giải pháp khắc phục sự bế tắc
- Dò tìm sự bế tắc khi chúng xảy ra và cố gắng khôi phục lại.
- Sử dụng các thông tin yêu cầu tài nguyên của các tiến trình để điều khiển sự
phân phối để khi tiếp tục phân phối các tài nguyên không là nguyên nhân để các
tiến trình rơi vào bế tắc.
- Ngăn cấm không để xảy ra điều kiện thứ 4 trong các điều kiện trên.
27
CHƯƠNG 3 - MPI TRONG THUẬT TOÁN DIJKSTRA CHO BÀI TOÁN
TÌM KIẾM ĐƯỜNG ĐI NGẮN NHẤT
3.1. Yêu cầu đặt ra cho bài toán tìm kiếm đường đi ngắn nhất theo giải
thuật Dijksta
Thuật toán Dijkstra có thể tính toán tất cả các đường đi ngắn nhất từ một đỉnh
xuất phát cho trước s tới mọi đỉnh khác mà không làm tăng thời gian chạy. Độ
phức tạp của thuật toán này là O(n2).
Yêu cầu đặt ra ở đây là với số đỉnh lớn, mỗi đỉnh có số cạnh kề lớn, chi phí để
tìm đường đi ngắn nhất tương ứng với thuật toán này là không nhỏ.
Để đáp ứng yêu cầu trên với chi phí thấp nhất, cần cải tiến thuật toán Dijkstra cổ
điển để đáp ứng yêu cầu về thời gian.
Trong luận văn này, tác giả đề xuất hướng giải quyết bằng cách song song hoá
thuật toán Dijkstra sử dụng mô hình truyền thông điệp MPI.
3.2. Xây dựng hàm tìm kiếm đường đi ngắn nhất
Phương pháp song song hoá được đề xuất trong luận văn là phương pháp chia
tập đỉnh nguồn. Với phương pháp này, mỗi bộ xử lý sẽ chạy thuật toán Dijkstra
tuần tự cho tập con các đỉnh nguồn.
Để xây dựng thuật toán Dijkstra song song, trước hết cần xây dựng thuật toán
Dijkstra tuần tự phù hợp với yêu cầu đặt ra.
3.2.1 Xây dựng thuật toán Dijkstra tuần tự cho bài toán
Procedure Seq Dijkstra (V,E,w,s)
Begin
28
VT:= {s};
For all v є (V-VT) do
If tồn tại cạnh (s, v) đặt l[v] := w(s, v);
else đặt L[v] := ∞;
while VT ≠ V do
Begin
Tìm một cạnh u mà L[u] := min{L[u]|v ϵ (V – VT)};
VT := VT ᴜ {u};
For all v ϵ (V – VT) do
L[v] := min{L[v], L[u] + w(u, v)};
End
Endwhile
End
End Pro
3.2.2 Thực hiện song song hoá
- Giả sử, bài toán có n đỉnh, thuật toán sử dụng p bộ xử lý.
- Tập đỉnh V được chia thành p tập con, mỗi tập con có n/p đỉnh và gán cho 1
bộ xử lý.
- Bộ xử lý Pi quản lý tập đỉnh con Vi và tính toán khoảng cách L[v] cho các
đỉnh v ϵ Vi
- Bộ xử lý Pi lưu phần Li của mảng L, tương ứng với tập con Vi
29
3.2.3 Thuật toán song song
Procedure Parallel Dijkstra (V,E,w,s)
Begin
VT:= {s};
For all v є (V-VT) do
If tồn tại cạnh (s, v) đặt L[v] := w(s, v);
else đặt L[v] := ∞;
Chia tập đỉnh V thành p tập con và gán cho mỗi tiến trình
while VT ≠ V do
Begin
Tại mỗi tiến trình, tìm một cạnh u mà Li[u] :=
min{Li[u]|v ϵ (V – VT)};
Kết hợp các giá trị min{Li-min | i = 0..p-1} từ tất cả các
tiến trình và phân phối trở lại tất cả các tiến trình
Đánh dấu đỉnh đã thực hiện
Cập nhật giá trị min trên mỗi tiến trình
End
Tổng hợp kết quả từ các tiến trình
Endwhile
End
End Pro
30
3.2.4 Lựa chọn hàm MPI cho thuật toán song song
Một chương trình MPI bao gồm nhiều chương trình tuần tự có trao đổi dữ liệu
với nhau thông qua việc gọi các hàm trong thư viện. Các hàm này thuộc bốn lớp
cơ bản:
1. Khởi tạo, quản lý và kết thúc trao đổi.
2. Trao đổi giữa hai tiến trình.
3. Trao đổi giữa một nhóm các tiến trình.
4. Tạo các định dạng dữ liệu bất kỳ.
Lớp đầu tiên là các hàm được gọi để khởi đầu quá trình trao đổi, xác định số
lượng bộ xử lý được sử dụng, tạo một nhóm con các bộ xử lý, xác định bộ xử lý
nào đang chạy chương trình hiện tại.
- MPI_Init(): khởi tạo quá trình song song.
- MPI_Finalize(): kết thúc quá trình song song.
- MPI_Comm_rank(): xác định tên tiến trình.
- MPI_Comm_size(): xác định tổng số tiến trình chạy song song.
Lớp thứ hai là các hàm, được gọi để trao đổi dữ liệu điểm - đến - điểm, với các
kiểu gửi và nhận dữ liệu khác nhau giữa hai bộ xử lý.
- MPI_Send(): gửi dữ liệu đến một tiến trình.
- MPI_Recv(): nhận dữ liệu từ một tiến trình.
Lớp thứ ba là các hàm cho phép thực hiện trao đổi song song giữa một nhóm các
bộ xử lý. Các hàm cơ bản:
31
- MPI_Bcast(): gửi dữ liệu từ một tiến trình đi tất cả các tiến trình.
- MPI_Reduce(): gửi dữ liệu từ nhiều tiến trình về một tiến trình
- MPI_Barrier(): dùng để đồng bộ hoạt động giữa các máy
- MPI_Gather(): nhận dữ liệu từ nhiều tiến trình.
- MPI_Scatter(): gửi dữ liệu đến nhiều tiến trình
Lớp cuối cùng là các hàm cung cấp để tạo ra các cấu trúc dữ liệu phức tạp riêng
của người dùng. Các hàm cơ bản:
- MPI_Type_struct(): tạo ra kiểu dữ liệu MPI riêng của người dùng
- MPI_Type_commit(): hòan thành quá trình định nghĩa kiểu dữ liệu MPI
Trong luận văn này, để thực hiện trao đổi song song giữa một nhóm các bộ xử lý
cần sử dụng các hàm ở lớp thứ 3.
* Hàm Reduce
Hàm Reduce nhận kết quả từ các tiến trình và gửi kết quả đó đến tiến trình đã
được chỉ định.
- Cú pháp: int MPI_ Reduce(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)
32
Hình 3.1: phương thức hoạt động của hàm Reduce
* Hàm All – Reduce
Hàm All – Reduce tương tự như hàm Reduce, nhưng không có Root và tất cả các
tiến trình đều nhận được kết quả.
* Hàm Broadcast
Hàm Boadcast cho phép một tiến trình gửi dữ liệu đến tất cả các tiến trình khác.
- Cú pháp: int MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int
root, MPI_Comm comm)
Hình 3.2: phương thức hoạt động của hàm Broadcast
33
* Hàm Scatter
Hàm Scatter chia nhỏ dữ liệu của một tiến trình và phân phối các phần dữ liệu
được chia lên các tiến trình khác.
- Cú pháp: int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
MPI_Comm comm)
Hình 3.3: phương thức hoạt động của hàm Scatter
* Hàm Gather
Một tiến trình được chỉ định sẽ nhận kết quả từ các tiến trình khác khi sử dụng
hàm Gather.
- Cú pháp: int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
MPI_Comm comm)
34
Hình 3.4: phương thức hoạt động của hàm Gather
* Hàm Gather – to – All
Tương tự như hàm Gather, nhưng tất cả các tiến trình đều nhận được kết quả như
nhau.
- Cú pháp: int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm
comm)
Hình 3.5: phương thức hoạt động của hàm Gather – to - All
* Hàm All – to – all
35
Hàm All –to – All cho phép tất cả các tiến trình phân chia dữ liệu, sau đó gửi
từng phần dữ liệu đến các tiến trình khác.
- Cú pháp: int MPI_All_to_all(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm
comm)
Hình 3.6: phương thức hoạt động của hàm All – to – All
Căn cứ vào đặc điểm của các hàm ở lớp 3, luận văn sử dụng:
- Hàm Reduce khi kết hợp các giá trị min;
- Hàm Broadcast để phân phối kết quả đến các tiến trình sau khi đã kết hợp;
- Hàm Gather để tập hợp các kết quả sau khi duyệt hết tất cả các đỉnh;
3.2.5 Công thức song song
- Tại bước kết nạp đỉnh s vào tập VT
- Bộ xử lý Pi tính Li(v) = min{ Li(v), Li(u) + w(v,r) }, v ∈ Vi \VT
- Sau đó, Pi tính Li-min = min{ Li(v) | v ∈ Vi \VT)
36
- Sử dụng mẫu liên lạc All-to-One Reduction để đưa min{Li-min | i = 0..p-1}
về P0
- Giả sử giá trị nhỏ nhất đạt được tại đỉnh u, P0 broadcast u đến các bộ xử lý
khác, bộ xử lý quản lý u sẽ đánh dấu u là không xét đến nữa.
37
* Sơ đồ khối thuật toán Dijkstra song song
Begin
Nếu
v є (V-VT)
L[v] := ∞
While VT ≠ V
Tìm u có trọng số
nhỏ nhất mà
v ϵ (V – VT)
Kết hợp
Li-min,
phân
phối trở
lại các
tiến
trình
Đánh dấu đỉnh đã thực hiện
Cập nhật giá trị min
trên mỗi tiến trình
End
Nếu tồn tại
(s,v)True
False
False
True
L[v] :=
w(s, v)True
Tổng hợp
kết quả từ
các tiến
trình
False
Hình 3.1: Sơ đồ khối thuật toán Dijkstra song song
38
3.3. Chi phí thời gian
- Mỗi bộ xử lý lưu n/p phần tử của mảng L
- Thời gian tính min và cập nhật giá trị của di bằng O(n/p)
- Thời gian liên lạc giữa p bộ xử lý O(log p)
- Tổng thời gian O(n2/p) + O(n log p)
- Tổng chi phí O(n2) + O(np log p)
- Để thuật toán là tối ưu chi phí p = O(n / log n)
39
CHƯƠNG 4 - KẾT QUẢ THỬ NGHIỆM
4.1. Các kết quả thử nghiệm
4.1.1. Kết quả thử nghiệm giải thuật Dijkstra cổ điển
* Phần cứng
- 1 máy tính Pentium IV 2.2GHz, RAM 512MB cài đặt hệ điều hành
CentOS.
* Thử nghiệm
- Cài đặt thuật toán Dijkstra cổ điển với số lượng đỉnh tăng dần, trọng số giữa
các cạnh được chọn ngẫu nhiên.
- Kết quả chạy thử nghiệm:
Bảng 4.1: Thời gian thực hiện thuật toán Dijkstra cổ điển
Số đỉnh Thời gian tuần tự (s)
0 0
500 0.004466
1000 0.010011
1500 0.023075
2000 0.03786
2500 0.061357
3000 0.09546
3500 0.134992
4000 0.176472
4500 0.230217
5000 0.292116
5500 0.362056
6000 0.426997
6500 0.503063
40
4.1.2. Kết quả thử nghiệm tìm kiếm bằng giải thuật Dijkstra song song
* Phần cứng
- Hệ thống bao gồm 2 máy tính Pentium IV 2.2GHz, RAM 512MB cài đặt
hệ điều hành CentOS.
- Hệ thống đã được cài đặt MPI.
* Thử nghiệm
- Cài đặt thuật toán Dijkstra song song với số lượng đỉnh tăng dần, trọng số
giữa các cạnh được chọn ngẫu nhiên.
- Số tiến trình thử nghiệm là 2, tương ứng với mỗi bộ xử lý là 1 tiến trình.
- Kết quả chạy thử nghiệm:
Bảng 4.2: Thời gian thực hiện thuật toán Dijkstra song song với 2 tiến trình
Số đỉnh Thời gian song song
(2 tiến trình)
0 0
500 0.006841
1000 0.013739
1500 0.027807
2000 0.048473
2500 0.07326
3000 0.103994
3500 0.141089
4000 0.181721
4500 0.233742
5000 0.282327
5500 0.348231
6000 0.409863
6500 0.485421
- Thay đổi số tiến trình, chạy thuật toán cho kết quả tương ứng như sau:
41
Bảng 4.3: Thời gian thực hiện thuật toán Dijkstra song song với nhiều tiến trình
Số đỉnh Thời gian song song
3 tiến trình 4 tiến trình
0 0 0
500 0.045354 0.088688
1000 0.108983 0.232677
1500 0.175406 0.403382
2000 0.264301 0.635685
2500 0.294662 0.769664
3000 0.334142 1.011743
3500 0.410569 1.313697
4000 0.476818 1.628063
4500 0.604493 2.019241
5000 0.656572 2.417935
5500 0.799673 2.867876
6000 0.858593 3.318057
6500 0.983601 3.981472
4.2. Đánh giá kết quả
- Kết quả thử nghiệm cho thấy rằng tốc độ thực hiện thuật toán Disktra song
song trên hệ thống thử nghiệm nhanh hơn tốc độ thực hiện thuật toán Dijkstra
trên một máy đơn.
42
0
0.1
0.2
0.3
0.4
0.5
0.6
0
10
00
20
00
30
00
40
00
50
00
60
00
Thời gian
song song
Thời gian
tuần tự
Hình 4.4: So sánh kết quả thử nghiệm thuật toán Dijksta
- Thuật toán Dijksta cổ điển cho thời gian xử lý ban đầu nhanh hơn, nhưng tỷ
lệ thời gian xử lý càng tăng khi thực hiện với số đỉnh càng lớn, thời gian thực
hiện lớn hơn.
- Thuật toán Dijkstra song song cho thời gian xử lý ban đầu lâu hơn, nhưng
tỷ lệ thời gian xử lý ổn định khi thực hiện với số đỉnh càng lớn, thời gian thực
hiện thấp hơn.
- Khi tăng số tiến trình xử lý lên 3, với số đỉnh thấp, số tiến trình cao sẽ xử lý
nhiều thời gian hơn do thời gian truyền thông tăng. Nhưng với số đỉnh càng tăng,
43
thời gian xử lý vẫn có tỷ lệ ổn định. Điều này cho thấy thuật toán vẫn chưa tối ưu
được thời gian cho chi phí truyền thông.
- Tăng số tiến trình lên 4, thời gian xử lý nhiều hơn, số đỉnh càng thì thời
gian xử lý càng tăng. Đặc biệt khi số đỉnh tăng lên cao thì thời gian xử lý càng
nhiều. Do đó trường hợp này không tối ưu cho thuật toán.
- Số tiến trình tăng, nhưng số bộ xử lý không tăng, nên chưa đánh giá được
hiệu suất của thuật toán.
0
0.5
1
1.5
2
2.5
3
3.5
4
4.5
0
10
00
20
00
30
00
40
00
50
00
60
00
2 Tiến trình
3 Tiến trình
4 tiến trình
Hình 4.5: So sánh kết quả thử nghiệm thuật toán Dijksta với nhiều tiến trình
44
KẾT LUẬN
Lập trình song song hiện nay không còn là công việc của một bộ phận của cộng
đồng các nhà khoa học, nghiên cứu, hoặc trong nền công nghiệp mà nó đã trở
thành xu hướng phát triển trong thời đại ngày nay. Việc tận dụng sức mạnh của
hệ thống máy tính với phương pháp lập trình song song đem lại lợi ích hơn nhiều
so với việc đầu tư một siêu máy tính với khả năng xử lý cao, nhưng hạn chế với
phương pháp xử lý tuần tự cổ điển.
Song song hoá thuật toán Dijkstra cho bài toán tìm đường đi ngắn nhất với MPI
cho kết quả tốt hơn so với thực hiện thuật toán Dijkstra cổ điển, điều này chứng
minh được lập trình song song có thể giúp các nhà nghiên cứu, khoa học hoặc
nền công nghiệp tận dụng được tối đa sức mạnh của hệ thống, đồng thời giảm
chi phí đầu tư hợp lý.
Luận văn đã giải quyết được yêu cầu đặt ra ban đầu cho đề tài. Tuy nhiên, việc
kiểm soát tài nguyên bộ nhớ của hệ thống vẫn chưa được giải quyết trong luận
văn này. Đây là một thách thức không nhỏ cho các nhà lập trình song song để
giải quyết vấn đề tối ưu về chi phí thực hiện lẫn chi phí bộ nhớ.
TÀI LIỆU THAM KHẢO
Tiếng Việt
[1] Đinh Mạnh Tường, Giáo trình trí tuệ nhân tạo, Khoa CNTT – Đại học Quốc
gia Hà Nội
[2] Giáo trình Lý thuyết đồ thị, Khoa CNTT – Đại học Huế
Tiếng Anh
[3] G. Amdahl. Validity of the single processor approach to achieving large scale
computing capabilities. Proc. AFIPS Conf., 30:483{485, Apr. 18-20 1967}.
[4] G.A.Geist, J.A.Kolh, P.M.Papadopoulos, PVM and MPI: a comparison of
features, Applied Mathematical Sciences subprogram of the Office of Energy
Reaseach, US Department of Energy. May 30 1996.