Contoh Beton
Saya ingin menambahkan beberapa contoh di dunia nyata, dan menghubungkannya ke dunia rekayasa perangkat lunak. Pertama, pertimbangkan sesuatu yang saya harap cocok dengan definisi intuitif Anda tentang "sinkron": kilatan kunang-kunang , dalam beberapa keadaan. Kedua, pertimbangkan lomba estafet Olimpiade 4x100 putri . Ketiga, perhatikan kiasan lama dari film-film militer: "Men, selaraskan jam tanganmu!"
Sekarang, mari kita pikirkan apa yang sedang terjadi. Mari kita mulai dengan mengamati bahwa semua ini adalah proses , atau entitas yang diperpanjang dalam waktu . Tidak masuk akal untuk mengatakan bahwa mangkuk "sinkron" dan batu "async." Kedua, butuh dua untuk tango . Anda tidak dapat mengatakan bahwa "seorang pelari adalah sinkronisasi". Sinkronkan dengan apa? Akhirnya, agar dua proses melakukan sesuatu pada saat yang sama, kecuali mereka sudah memiliki frekuensi dan fase yang sama persis, satu atau keduanya harus menunggu .
Analisis
Ketika definisi kamus mengatakan dua entitas dalam sinkronisasi "terjadi atau ada pada saat yang sama", itu sangat sesuai dengan konsep cahaya dari kunang-kunang. Sayangnya, mengatakan bahwa cahaya "sinkron" adalah cara ceroboh untuk mengatakan bahwa proses pencahayaan kunang - kunang disinkronkan.
Jadi bagaimana sekelompok kunang-kunang, yang mungkin tidak memiliki Apple SmartWatch dan NTP untuk membimbing mereka, berhasil mem-flash ujung belakang mereka pada saat yang sama? Yah, itu sangat mudah jika mereka memiliki sarana untuk mengatur tempo yang konsisten dan dapat membuat sedikit penyesuaian untuk itu. Mereka hanya berkedip, dan jika lebih banyak orang melakukan flash tepat setelah mereka, mereka melambat (menambah penundaan), sedangkan jika lebih banyak berkedip tepat sebelum mereka, mereka mempercepat (mengurangi penundaan). Jadi mereka dapat menggunakan proses umpan balik sederhana untuk sampai pada dasarnya pada tempo dan fase yang sama. Pengamatan penting di sini adalah untuk mencatat bahwa mereka mencapai sinkronisasi dengan menunggu saat yang tepat untuk mem-flash .
Balapan 4x100 menarik karena Anda melihat kedua bentuk waktu proses dalam aksi: pelari dalam tim disinkronkan, sedangkan pelari di tim yang berbeda adalah "async". Pelari kedua dalam relai harus menunggu sampai pelari pertama memasuki zona transfer . Hand-off adalah acara sinkron antara kedua pelari tersebut. Namun, pelari di lajur yang berbeda tidak peduli apa yang terjadi di lajur lain , dan tentu saja tidak memperlambat dan melakukan hand-off secara sinkron. Setiap jalur pelari tidak sinkron sehubungan dengan satu sama lain. Sekali lagi, kita melihat bahwa sinkronisasi mensyaratkan menunggu, sedangkan asynchrony tidak.
Akhirnya, prajurit di kompi (peleton, tim pemadam kebakaran, dll.) Harus menyinkronkan arloji mereka sehingga mereka dapat menyerang musuh pada saat bersamaan . Mungkin beberapa tentara tiba di posisi mereka di depan yang lain, atau memiliki kesempatan untuk menembak musuh lebih cepat. Tetapi serangan simultan umumnya lebih efektif daripada serangan serampangan karena unsur kejutan. Jadi untuk mencapai sinkronisasi, banyak tentara harus menunggu waktu yang ditentukan untuk bertindak.
Mendefinisikan Fitur
Mengapa penekanan ini menunggu? Yah, itu karena menunggu adalah fitur penentu yang membedakan proses sinkron dan asinkron. Jika Anda memiliki dua proses yang tidak Anda ketahui, Anda harus, secara default, menganggap bahwa keduanya tidak sinkron. Misalnya, pengiriman paket dan ambulans yang dikendarai kemungkinan besar tidak disinkronkan. Untuk menunjukkan bahwa dua proses, pada kenyataannya, disinkronkan, Anda perlu menemukan momen yang sangat istimewa: titik sinkronisasi .
Pengemudi yang mengantar paket dan ambulans yang membawa seseorang ke rumah sakit biasanya tidak membagikan poin waktu yang kami identifikasi sebagai "titik sinkronisasi". Di sisi lain, kunang-kunang yang berkedip serentak memiliki titik sinkronisasi setiap kali mereka berkedip, pelari estafet memiliki titik sinkronisasi setiap kali mereka melepaskan tongkat pemukul, dan tentara memiliki titik sinkronisasi ketika mereka meluncurkan serangan mereka. Jika Anda dapat mengidentifikasi satu atau beberapa titik sinkronisasi, maka proses akan disinkronkan . Ini harus mudah dimengerti, karena "syn-" adalah awalan bahasa Yunani yang berarti "dengan" atau "bersama", dan "chrono" adalah akar bahasa Yunani untuk "waktu". "Disinkronkan" secara harfiah berarti "pada saat yang sama",
Batas
Perhatikan bahwa "sinkronisasi" tidak selalu berlaku untuk seluruh masa hidup salah satu atau kedua proses. Saya berpendapat bahwa itu hanya berlaku untuk "waktu tunggu hingga dan termasuk titik sinkronisasi" (s) ". Dengan demikian, dua proses dapat beroperasi secara tidak sinkron sampai mereka mencapai keadaan di mana mereka perlu berkomunikasi, kemudian mereka menjadi tersinkronisasi, bertukar informasi, dan kemudian melanjutkan secara tidak sinkron. Contoh sederhana adalah bertemu seseorang untuk minum kopi. Jelas, rapat adalah titik sinkronisasi (atau banyak, lebih tepatnya), dan fakta bahwa dua orang tiba pada titik itu menunjukkan sinkronisasi. Namun, kami tidak akan mengatakan itu karena dua orang bertemu untuk minum kopi, dua kehidupan manusia itu"disinkronkan". Mungkin itulah satu-satunya momen instan dalam kehidupan mereka yang mereka temui, dan semua hal lain yang mereka lakukan adalah independen.
Ini juga bukan kasus yang kebetulan bertemu menunjukkan sinkroni. Jika dua orang asing saling berpapasan di jalan, fakta bahwa mereka berada di tempat tertentu pada suatu waktu tidak membuktikan keserasian. Juga tidak ada fakta bahwa satu orang duduk di bangku menunggu bus, dan yang lainnya kebetulan lewat. Proses hanya sinkron ketika mereka bertemu untuk suatu tujuan .
Koneksi Perangkat Lunak
Sekarang, mari kita pikirkan tentang tugas yang sangat mendasar dalam perangkat lunak: membaca dari file. Seperti yang mungkin Anda ketahui, penyimpanan massal biasanya ribuan hingga jutaan kali lebih lambat daripada cache atau memori utama. Untuk alasan ini, sistem operasi dan perpustakaan bahasa pemrograman umumnya menawarkan operasi I / O yang sinkron dan asinkron. Sekarang, bahkan jika program Anda hanya memiliki satu utas, Anda harus menganggap OS sebagai "proses terpisah" untuk keperluan diskusi ini.
Sinkronkan
Ketika Anda membuat "I / O sinkron membaca", utas Anda harus menunggu hingga data tersedia, pada titik mana itu berlanjut. Ini sangat mirip dengan pelari estafet yang menyerahkan tongkat estafet ke pelari berikutnya, tetapi bayangkan sebuah estafet dengan hanya dua pelari yang berjalan sepanjang lintasan, dan pelari kedua juga menyerahkan kembali ke pelari yang pertama.
Dalam hal ini, utas program Anda dan proses I / O OS tidak "terjadi (berakting) pada saat yang sama", dan jadi aneh rasanya mengatakan bahwa proses ini "disinkronkan". Tapi itu cara yang salah untuk melihatnya! Itu seperti mengatakan: "Pelari di tim estafet tidak berlari pada saat yang sama, jadi mereka tidak disinkronkan." Faktanya, kedua pernyataan itu salah! Pelari dalam tim estafet melakukan dan harus berlari pada waktu yang sama, tetapi hanya pada saat yang sangat spesifik: penyerahan tongkat estafet. Faktanya, hanya momen spesial ini selama balapan yang meyakinkan kami bahwa tim estafet telah disinkronkan untuk memulainya! Jika kita melihat permintaan dan respons I / O sebagai "tongkat",
Di sisi lain, jika kita berpikir tentang sesuatu seperti Analisis Elemen Hingga pada superkomputer, kita melihat bahwa ribuan proses harus bekerja dalam langkah kunci untuk memperbarui keadaan global yang masif. Bahkan jika beberapa node menyelesaikan pekerjaan mereka untuk langkah waktu tertentu sebelum yang lain, mereka semua harus menunggu langkah waktu untuk menyelesaikan karena hasilnya menyebar ke tetangga melalui ruang. Sinkronisasi semacam ini seperti kunang-kunang: semua aktor melakukan tugas yang sama.
Varietas proses
Untuk alasan ini, kami dapat menemukan beberapa istilah untuk membantu kami melihat bahwa ada tiga jenis hal yang terjadi: "sinkronisasi homogen", "sinkronisasi heterogen", dan "sinkronisasi berurutan". Jadi ketika para aktor melakukan tugas yang sama secara bersamaan (FEA, kunang-kunang), mereka "homogen". Ketika mereka melakukan tugas yang berbeda secara bersamaan (tentara berlari vs merangkak vs berenang ke tujuan mereka, fisika vs suara vs benang AI dalam permainan), mereka "heterogen". Ketika mereka melakukan tugas satu per satu, mereka "berurutan" (relay runner, memblokir I / O). Mereka mungkin terlihat sangat berbeda, tetapi mereka memiliki satu properti penting: semua jenis aktor melakukan beberapa penantian untuk memastikan bahwa setiap orang tiba pada titik sinkronisasi pada saat yang sama. di antara titik-titik sinkronisasi, atau "melakukan tindakan yang sama" tidak relevan dengan properti sinkronisasi.
Pipeline render dalam GPU sinkron karena mereka semua harus menyelesaikan frame bersama, dan memulai frame baru bersama. Mereka homogen karena mereka melakukan jenis pekerjaan yang sama, dan mereka semua aktif bersama. Tetapi loop permainan utama dari server dan memblokir I / O thread yang memproses input jarak jauh heterogen karena mereka melakukan berbagai jenis pekerjaan, dan beberapa thread I / O tidak akan melakukan apa-apa sama sekali, karena tidak semua koneksi digunakan. Meski begitu, mereka disinkronkan, karena mereka harus berbagi keadaan secara atom (pemain tidak harus melihat pembaruan dunia permainan parsial, dan server juga tidak hanya melihat sebagian input pemain).
Async
Sekarang, mari kita pertimbangkan "async I / O read". Ketika program Anda mengirim permintaan ke OS untuk membaca sedikit data dari penyimpanan, panggilan akan segera kembali . Mari kita abaikan panggilan balik dan fokus pada pemungutan suara. Secara umum, saat data tersedia untuk program Anda tidak sesuai dengan titik waktu tertentu sejauh menyangkut utas program Anda. Jika program Anda tidak secara eksplisit menunggu data, maka utas tersebut tidak akan tahu persis kapan momen itu terjadi. Itu hanya akan menemukan bahwa data sedang menunggu saat berikutnya memeriksa.
Tidak ada waktu pertemuan khusus di mana OS dan utas program setuju untuk menyerahkan data. Mereka seperti dua kapal yang lewat di malam hari. Asynchrony ditandai dengan tidak adanya menunggu. Tentu saja, utas program seringkali berakhir pada menunggu operasi I / O, tetapi tidak perlu. Itu bisa dengan senang melanjutkan melakukan perhitungan lain saat pengambilan I / O terjadi, dan hanya memeriksa nanti ketika ada waktu luang. Tentu saja, begitu OS selesai mengambil data, ia juga tidak menunggu. Itu hanya menempatkan data di tempat yang nyaman dan melanjutkan bisnisnya. Dalam hal ini, itu seperti program menyerahkan tongkat ke OS, dan OS muncul kemudian, menjatuhkan tongkat di tanah bersama dengan data, dan berjalan keluar dari trek. Program mungkin atau mungkin tidak menunggu untuk menerima hand-off.
Paralelisme
Ketika kita menandai fungsi sebagai "async" dalam perangkat lunak, itu sering berarti kita menginginkan paralelisme . Tetapi ingat bahwa paralelisme tidak menyiratkan sinkronisasi . Kunang-kunang adalah contoh yang baik, karena mereka juga menunjukkan perilaku sinkron dan asinkron. Sementara sebagian besar lalat melintas serempak, banyak yang jelas tidak selaras dengan anggota kelompok lainnya dan melintas lebih acak. Lalat-lalat itu mungkin bertindak secara simultan , tetapi tidak semuanya disinkronkan .
Sekarang ketika kita menandai beberapa kode sebagai "async", itu terlihat lucu, karena itu menyiratkan bahwa sisa kode yang tidak ditandai adalah "sinkronisasi". Apa artinya itu? Bukankah kita bersikeras bahwa "sinkronisasi" memerlukan dua tango? Tetapi bagaimana jika kita berbicara tentang mengeksekusi kode dalam satu utas? Dalam hal ini, kita perlu mengambil langkah mundur dan berpikir tentang program sebagai urutan negara dan transisi antara negara-negara tersebut. Pernyataan dalam suatu program menyebabkan transisi negara. Kita dapat menganggapnya sebagai "proses mikro" yang dimulai dan berhenti dengan pernyataan. Titik-titik urutan yang ditentukan oleh bahasa tersebut, pada kenyataannya, adalah titik sinkronisasi dari "proses-mikro" ini. Dan dengan demikian, kita dapat melihat single-threaded,
Integritas bahasa pemrograman menjamin bahwa pembaruan negara tidak mengganggu pernyataan, dan titik urutan menentukan batas di mana kompiler tidak diizinkan untuk membuat optimasi yang dapat diamati. Misalnya, urutan evaluasi ekspresi dalam pernyataan mungkin tidak ditentukan atau tidak ditentukan, memberikan kebebasan kompilator untuk mengoptimalkan pernyataan dalam berbagai cara. Tetapi pada saat pernyataan berikutnya dimulai, program harus dalam keadaan yang terdefinisi dengan baik, jika PL itu sendiri sehat.
Sekarang, sudah jelas apa yang kita maksud dengan "async". Ini berarti persis bahwa kontrak sinkronisasi yang tersirat dalam satu blok kode dikecualikan untuk blok async. Diperbolehkan untuk memperbarui status program secara independen, tanpa jaminan keselamatan yang biasanya ditunjukkan oleh model perhitungan sekuensial (konsisten, sinkron). Tentu saja, ini berarti bahwa kita perlu berhati-hati agar tidak merusak keadaan program dengan tidak konsisten. Ini biasanya berarti bahwa kami memperkenalkan sinkronisasi eksplisit dan terbatas untuk berkoordinasi dengan blok async. Perhatikan bahwa ini berarti blok async dapat asinkron dan sinkron pada waktu yang berbeda! Tetapi mengingat bahwa sinkronisasi hanya menunjukkan keberadaan titik sinkronisasi, kita seharusnya tidak kesulitan menerima gagasan ini.