Pemrograman fungsional tidak membuat untuk program yang lebih cepat, sebagai aturan umum. Apa yang membuatnya adalah untuk pemrograman paralel dan bersamaan yang lebih mudah . Ada dua kunci utama untuk ini:
- Menghindari keadaan yang bisa berubah cenderung mengurangi jumlah hal yang bisa salah dalam suatu program, dan bahkan lebih lagi dalam program bersamaan.
- Menghindari primitif berbagi-memori dan sinkronisasi berbasis kunci yang mendukung konsep-konsep tingkat tinggi cenderung menyederhanakan sinkronisasi antara utas kode.
Salah satu contoh bagus dari poin # 2 adalah bahwa di Haskell kita memiliki perbedaan yang jelas antara paralelisme deterministik vs konkurensi non-deterministik . Tidak ada penjelasan yang lebih baik selain mengutip buku Simon Marlow yang sangat bagus Parallel and Concurrent Programming di Haskell (kutipan dari Bab 1 ):
Sebuah program paralel adalah salah satu yang menggunakan banyaknya hardware komputasi (misalnya, beberapa core prosesor) untuk melakukan perhitungan lebih cepat. Tujuannya adalah untuk sampai pada jawaban sebelumnya, dengan mendelegasikan bagian-bagian berbeda dari perhitungan ke prosesor yang berbeda yang mengeksekusi pada waktu yang sama.
Sebaliknya, konkurensi adalah teknik penataan program di mana ada banyak untaian kontrol. Secara konseptual, utas kontrol menjalankan "pada saat yang sama"; yaitu, pengguna melihat efeknya disisipkan. Apakah mereka benar-benar mengeksekusi pada saat yang sama atau tidak adalah detail implementasi; program konkuren dapat dijalankan pada satu prosesor melalui eksekusi berlevel atau pada beberapa prosesor fisik.
Selain itu, Marlow juga menyebutkan dimensi determinisme :
Perbedaan terkait adalah antara model pemrograman deterministik dan nondeterministik . Model pemrograman deterministik adalah model di mana setiap program hanya dapat memberikan satu hasil, sedangkan model pemrograman nondeterministik mengakui program yang mungkin memiliki hasil yang berbeda, tergantung pada beberapa aspek pelaksanaannya. Model pemrograman konkuren tidak bersifat deterministik karena mereka harus berinteraksi dengan agen eksternal yang menyebabkan peristiwa pada waktu yang tidak terduga. Nondeterminisme memiliki beberapa kelemahan, namun: Program menjadi lebih sulit untuk diuji dan dipikirkan.
Untuk pemrograman paralel, kami ingin menggunakan model pemrograman deterministik jika memungkinkan. Karena tujuannya hanya untuk mencapai jawaban lebih cepat, kami lebih suka tidak membuat program kami lebih sulit untuk di-debug dalam proses. Pemrograman paralel deterministik adalah yang terbaik dari kedua dunia: Pengujian, debugging, dan penalaran dapat dilakukan pada program berurutan, tetapi program berjalan lebih cepat dengan penambahan lebih banyak prosesor.
Dalam Haskell fitur paralelisme dan konkurensi dirancang di sekitar konsep-konsep ini. Secara khusus, apa yang dikelompokkan oleh bahasa lain sebagai satu set fitur, Haskell terbagi menjadi dua:
- Fitur deterministik dan perpustakaan untuk paralelisme .
- Fitur dan pustaka non-deterministik untuk konkurensi .
Jika Anda hanya ingin mempercepat perhitungan yang murni dan deterministik, memiliki paralelisme deterministik sering membuat segalanya lebih mudah. Seringkali Anda hanya melakukan sesuatu seperti ini:
- Tulis fungsi yang menghasilkan daftar jawaban, yang masing-masing mahal untuk dihitung tetapi tidak terlalu bergantung satu sama lain. Ini Haskell, jadi daftar-daftar itu malas — nilai-nilai elemen mereka tidak benar-benar dihitung sampai konsumen menuntutnya.
- Gunakan pustaka Strategies untuk menggunakan elemen daftar hasil fungsi Anda secara paralel di beberapa core.
Saya benar-benar melakukan ini dengan salah satu program proyek mainan saya beberapa minggu yang lalu . Itu sepele untuk memparalelkan program - hal utama yang harus saya lakukan adalah, pada dasarnya, menambahkan beberapa kode yang mengatakan "menghitung elemen-elemen dari daftar ini secara paralel" (baris 90), dan saya mendapat peningkatan throughput linear dekat pada beberapa kasus pengujian saya yang lebih mahal.
Apakah program saya lebih cepat daripada jika saya menggunakan utilitas multithreading berbasis kunci konvensional? Saya sangat meragukannya. Hal yang rapi dalam kasus saya adalah mendapatkan begitu banyak dari begitu sedikit uang — kode saya mungkin sangat suboptimal, tetapi karena sangat mudah untuk memaralelkan saya mendapat percepatan yang besar dari itu dengan usaha yang jauh lebih sedikit daripada dengan benar membuat profil dan mengoptimalkannya, dan tidak ada risiko kondisi balapan. Dan itu, saya akan klaim, adalah cara utama pemrograman fungsional memungkinkan Anda untuk menulis program "lebih cepat".