Vektorisasi, preallocation, dan optimasi function memeras satu core habis-habisan — sementara mesin modern punya banyak core yang menganggur. Parallel Computing Toolbox menyalurkan pekerjaan MATLAB ke banyak worker lewat parfor, parfeval, dan spmd. Kabar jujurnya: paralel bukan tombol ajaib; overhead komunikasi dan bagian kode yang tetap serial sering membatalkan keuntungannya. Chapter ini membangun intuisinya dulu, baru sintaksnya. Cakupan materinya:

  • Konsep task parallel vs data parallel, dan parpool sebagai kumpulan worker
  • parfor: syarat kemandirian iterasi, reduction dan broadcast variable
  • Hukum Amdahl: speedup maksimum dibatasi fraksi serial (demo teruji)
  • parfeval dan spmd sekilas, plus padanan portabel tanpa toolbox

Task Parallel vs Data Parallel #

Dua pola paralel mendominasi praktik. Task parallel memecah pekerjaan yang berbeda ke beberapa worker: satu worker membaca file, satu lagi menghitung statistik. Data parallel menjalankan pekerjaan yang sama pada potongan data yang berbeda: setiap worker mengolah sepertiga elemen array. parfor adalah kendaraan data parallel — membagi rentang iterasi ke worker; parfeval kendaraan task parallel — mengantarkan satu tugas ke worker mana pun yang kosong.

AspekTask parallelData parallel
Unit kerjaTugas berbeda per workerTugas sama, data berbeda
Alat MATLABparfeval, spmdparfor, gpuArray
Contohbaca CSV + hitung + plot bersamaansqrt(x) pada 10 juta elemen
Cocok untukpipeline, simulasi parameterloop independen berskala besar

parpool dan parfor #

parpool memulai kumpulan worker — proses MATLAB terpisah yang siap menerima pekerjaan. Panggilan parpool tanpa argumen memakai default profile; parpool(4) secara eksplisit meminta empat worker. parfor lalu membagikan iterasi loop ke worker di pool tersebut:

matlab
parpool(4);                 % MATLAB-ONLY: mulai 4 worker

n = 1e6;
v = rand(n, 1);
total = 0;                  % reduction variable
hasil = zeros(1, n);        % sliced variable

parfor k = 1:n
    total = total + v(k);   % tiap iterasi membaca v, menambah total
    hasil(k) = v(k)^2;      % tiap iterasi menulis potongan sendiri
end

Mari kita bedah baris-baris kode di atas:

  1. Baris 1 (parpool(4);): membuat 4 proses worker; startup-nya sendiri memakan detik — biaya tetap yang harus ditutup keuntungan paralel.
  2. Baris 5 (total = 0;): total adalah reduction variable — parfor mengenali pola total = total + ... dan menggabungkan kontribusi tiap worker dengan aman.
  3. Baris 6 (hasil = zeros(1, n);): hasil adalah sliced variable — tiap iterasi menulis hasil(k) miliknya sendiri, tidak saling menginjak.
  4. Baris 8-11 (parfor k = 1:n): rentang iterasi dibagi ke worker; v dibaca semua worker sebagai broadcast variable (baca saja, tidak diubah).

Syarat mutlak parfor: setiap iterasi harus independen — dokumentasi resmi menegaskan iterasi dieksekusi tanpa urutan terjamin, dan script tidak boleh dipanggil langsung di dalam parfor (function boleh). Iterasi yang memakai hasil iterasi sebelumnya bukan sekadar lambat — hasilnya salah karena belum tentu terhitung.

Mengapa Paralel Tidak Selalu Lebih Cepat #

Tiga biaya menunggu: startup parpool, pengiriman data ke worker (variabel di-broadcast lewat memori bersama), dan penggabungan hasil. Di atas semuanya berdiri hukum Amdahl: bila fraksi f dari waktu program tetap serial, speedup dengan p worker dibatasi 1 / (f + (1 - f) / p) — bagian serial tidak ikut menyusut. Tabel berikut dihitung langsung oleh contoh.m:

matlab
pekerja = [2 4 8 16];
fraksi  = [0.05 0.10 0.25 0.50];

fprintf('Amdahl: speedup = 1 / (f + (1 - f) / p)\n');
fprintf('     f');
for p = pekerja
    fprintf('  p=%-2d', p);
end
fprintf('\n');
for f = fraksi
    fprintf('%6.2f', f);
    for p = pekerja
        speedup = 1 / (f + (1 - f) / p);
        fprintf('%6.1f', speedup);
    end
    fprintf('\n');
end
fprintf('f = fraksi waktu yang tetap serial, p = jumlah worker\n\n');

Output yang Dihasilkan:

text
Amdahl: speedup = 1 / (f + (1 - f) / p)
     f  p=2   p=4   p=8   p=16
  0.05   1.9   3.5   5.9   9.1
  0.10   1.8   3.1   4.7   6.4
  0.25   1.6   2.3   2.9   3.4
  0.50   1.3   1.6   1.8   1.9
f = fraksi waktu yang tetap serial, p = jumlah worker

Bacaan tabelnya: dengan 50% waktu serial, 16 worker hanya membeli speedup 1.9x. Meski program kita hanya 5% serial, 16 worker mentok di 9.1x — bukan 16x. Hukum Gustafson menyeimbangkan pesimisme ini: pada masalah yang membesar bersama jumlah worker, paralel tetap membeli kapasitas komputasi total yang jauh lebih besar; Amdahl menggambarkan satu program tetap, Gustafson menggambarkan masalah yang tumbuh.

parfeval dan spmd Sekilas #

parfeval menjadwalkan fungsi berjalan asinkron di worker dan langsung mengembalikan Future object — MATLAB tidak menunggu:

matlab
% MATLAB-ONLY
f = parfeval(@hitungStatistik, 1, data);   % 1 output, jadwalkan sekarang
laporan = buatLaporan();                   % ...kerjakan hal lain sambil menunggu
hasil = fetchOutputs(f);                   % ambil hasil saat dibutuhkan

Dokumentasi resmi menambahkan kabar ramah: tanpa pool dan tanpa toolbox, parfeval menjalankan fungsinya secara serial — kode tetap portabel untuk rekan tanpa Parallel Computing Toolbox. spmd (single program, multiple data) menjalankan blok yang sama di semua worker sekaligus, dengan spmdIndex sebagai identitas worker dan spmdSize sebagai jumlah worker; hasil yang keluar dari blok spmd menjadi Composite yang diakses per worker (s{2}). Gunakan spmd saat worker perlu saling berkomunikasi — domain distributed array di luar lingkup chapter ini.

Padanan Portable: Menguji Kemandirian Iterasi #

Tanpa toolbox pun, kita bisa membuktikan dua sifat yang menjadi syarat parfor. Pertama, iterasi independen menghasilkan jawaban yang sama dalam urutan apa pun (jumlah bilangan bulat tidak peduli urutan). Kedua, iterasi bergantung rusak bila urutannya diacak:

matlab
rng(42);
n = 12;
v = randi([1 50], 1, n);

totalUrut = 0;
for k = 1:n
    totalUrut = totalUrut + v(k);
end

acak = randperm(n);        % parfor tidak menjamin urutan eksekusi
totalAcak = 0;
for k = acak
    totalAcak = totalAcak + v(k);
end
fprintf('iterasi independen: urut %d | acak %d | identik %d\n', ...
    totalUrut, totalAcak, isequal(totalUrut, totalAcak));

Jumlah bilangan bulat tidak peduli urutan — iterasi seperti ini aman untuk parfor. Loop kedua kebalikannya: saldo(k) membutuhkan saldo(k-1), sehingga mengacak urutan eksekusi menghasilkan jawaban salah:

matlab
saldo = zeros(1, n);
saldo(1) = v(1);
for k = 2:n
    saldo(k) = saldo(k - 1) + v(k);   % butuh hasil iterasi sebelumnya
end

salah = zeros(1, n);
for k = acak
    if k == 1
        salah(1) = v(1);
    else
        salah(k) = salah(k - 1) + v(k);   % saldo(k-1) bisa masih 0
    end
end
fprintf('iterasi bergantung: benar = %d | urutan acak identik = %d\n\n', ...
    isequal(saldo, cumsum(v)), isequal(saldo, salah));

Output yang Dihasilkan:

text
iterasi independen: urut 242 | acak 242 | identik 1
iterasi bergantung: benar = 1 | urutan acak identik = 0

Loop kedua sengaja dijalankan dengan urutan acak: nilai saldo(k-1) bisa masih nol saat dibutuhkan, sehingga hasilnya melenceng dari cumsum(v) — inilah bentuk kegagalan yang sama bila iterasi bergantung dipaksakan ke parfor. Terakhir, contoh.m menutup dengan padanan manual parfor: membagi satu juta elemen ke empat potongan, tiap potongan dijumlahkan sendiri (reduction per bagian), lalu hasil bagian digabung — totalnya identik dengan sum(data).

Ringkasan #

Paralel dimulai dari parpool dan parfor, dengan dua kewajiban: iterasi independen (terbukti rusak pada demo urutan acak) dan pemahaman variabel — reduction, sliced, dan broadcast. Hukum Amdahl menjaga ekspektasi: 5% serial mentok di 9.1x untuk 16 worker; startup pool dan komunikasi memotong lagi. parfeval mengantarkan tugas asinkron, spmd menjalankan blok serentak dengan identitas spmdIndex. Ketika jumlah core masih kurang dan datanya jutaan elemen seragam, satu arah lagi terbuka: GPU — chapter berikutnya.