
Setiap bahasa yang mendukung komputasi paralel (kompetitif, tidak sinkron) memerlukan cara untuk menjalankan kode secara paralel. Berikut adalah contoh dari API yang berbeda:
go myfunc(); // Golang pthread_create(&thread_id, NULL, &myfunc); /* C with POSIX threads */ spawn(modulename, myfuncname, []) % Erlang threading.Thread(target=myfunc).start() # Python with threads asyncio.create_task(myfunc()) # Python with asyncio
Ada banyak opsi untuk notasi dan terminologi, tetapi satu semantik adalah menjalankan myfunc
secara paralel dengan program utama dan melanjutkan utas eksekusi induk (Aliran Kontrol)
Pilihan lain adalah Callback :
QObject::connect(&emitter, SIGNAL(event()), // C++ with Qt &receiver, SLOT(myfunc())) g_signal_connect(emitter, "event", myfunc, NULL) /* C with GObject */ document.getElementById("myid").onclick = myfunc; // Javascript promise.then(myfunc, errorhandler) // Javascript with Promises deferred.addCallback(myfunc) # Python with Twisted future.add_done_callback(myfunc) # Python with asyncio
Dan lagi, notasi berubah, tetapi semua contoh membuatnya sehingga, mulai dari saat ini, jika dan ketika peristiwa tertentu terjadi, maka myfunc
mulai. Setelah panggilan balik diatur, kontrol kembali dan fungsi panggilan berlanjut. (Kadang-kadang panggilan balik dibungkus dengan fungsi menggabungkan yang nyaman atau protokol gaya bengkok , tetapi ide dasarnya tidak berubah.)
Dan ... Itu saja. Ambil bahasa tujuan umum konkurensi populer dan Anda mungkin akan menemukan bahwa itu termasuk dalam salah satu paradigma ini (kadang-kadang keduanya, asyncio).
Tapi bukan perpustakaan Trio baruku yang aneh. Dia tidak menggunakan pendekatan ini. Sebaliknya, jika kita ingin menjalankan myfunc
dan myfunc
secara paralel, kita menulis sesuatu seperti ini:
async with trio.open_nursery() as nursery: nursery.start_soon(myfunc) nursery.start_soon(anotherfunc)
pembibitan - pembibitan, pembibitan
Untuk pertama kalinya dihadapkan dengan desain "kamar anak-anak", orang-orang tersesat. Mengapa ada manajer konteks (dengan-blok)? Apa pembibitan ini, dan mengapa diperlukan untuk menjalankan tugas? Kemudian orang-orang mengerti bahwa kamar anak mengganggu pendekatan yang biasa dalam kerangka kerja lain dan menjadi marah. Semuanya tampak aneh, spesifik, dan terlalu tinggi untuk menjadi primitif dasar. Semua ini adalah reaksi yang bisa dimengerti! Tapi bersabarlah sedikit.
Dalam artikel ini, saya ingin meyakinkan Anda bahwa pembibitan bukan iseng-iseng, melainkan primitif baru untuk mengendalikan aliran eksekusi, sama mendasarnya dengan loop dan pemanggilan fungsi. Selain itu, pendekatan yang dibahas di atas (membuat utas dan mendaftarkan panggilan balik) perlu dibuang dan diganti oleh pembibitan.
Kedengarannya terlalu berani? Tapi ini sudah terjadi: sekali goto
digunakan secara luas untuk mengendalikan perilaku suatu program. Sekarang ini adalah kesempatan untuk tertawa:

Beberapa bahasa masih memiliki apa yang disebut goto
, tetapi kemampuannya jauh lebih terbatas daripada goto
asli. Dan dalam sebagian besar bahasa tidak sama sekali. Apa yang terjadi padanya? Kisah ini secara mengejutkan relevan, meskipun tidak dikenal oleh kebanyakan orang karena jaman dahulu. Mari kita ingatkan diri kita sendiri apa goto
, dan kemudian lihat bagaimana ini dapat membantu dalam pemrograman asinkron.
Daftar isi
- Apa itu goto?
- Apa yang pergi
- Apa yang terjadi dengan goto?
- goto menghancurkan abstraksi
- Dunia baru yang berani tanpa goto
- Tidak ada lagi kebohongan
- Tentang bahaya ekspresi tipe "Go"
- pergi ekspresi mematahkan abstraksi.
- go-expressions memecah pembersihan otomatis sumber daya terbuka.
- ekspresi express penanganan kesalahan.
- Tidak ada lagi
- Pembibitan sebagai pengganti struktural untuk pergi
- Pembibitan mempertahankan abstraksi fungsi.
- Nursery mendukung penambahan tugas yang dinamis.
- Anda masih bisa meninggalkan kamar bayi.
- Anda dapat mengidentifikasi jenis baru yang dukun sebagai kamar bayi.
- Tidak, bagaimanapun, pembibitan selalu menunggu untuk menyelesaikan semua tugas di dalam.
- Bekerja membersihkan sumber daya secara otomatis.
- Pekerjaan peningkatan bug.
- Dunia baru yang berani tanpa pergi
- Pembibitan dalam praktik
- Kesimpulan
- Komentar
- Ucapan Terima Kasih
- Catatan kaki
- Tentang penulis
- Lanjutan
Apa itu goto
?
Komputer pertama diprogram menggunakan assembler , atau bahkan lebih primitif. Ini sangat tidak nyaman. Jadi pada 1950-an, orang-orang seperti John Backus dari IBM dan Grace Hopper dari Remington Rand mulai mengembangkan bahasa seperti FORTRAN dan FLOW-MATIC (lebih dikenal dengan COBOL turunan langsungnya).
FLOW-MATIC sangat ambisius pada saat itu. Anda dapat menganggapnya sebagai kakek buyut Python - itu adalah bahasa pertama yang dikembangkan terutama untuk orang-orang, dan yang kedua untuk komputer. Dia terlihat seperti ini:

Perhatikan bahwa tidak seperti bahasa modern, tidak ada kondisional if
blok, loop atau panggilan fungsi - sebenarnya tidak ada blok atau indentasi sama sekali. Ini hanya daftar ekspresi berurutan. Bukan karena program ini terlalu pendek untuk memerlukan pernyataan kontrol (selain JUMP TO
) - hanya sintaks yang belum ditemukan!

Sebagai gantinya, FLOW-MATIC memiliki dua opsi untuk mengontrol aliran eksekusi. Biasanya aliran itu konsisten - mulai dari atas dan bergerak ke bawah, satu ekspresi pada satu waktu. Tetapi jika Anda menjalankan ekspresi JUMP TO
khusus, itu bisa mengambil kendali di tempat lain. Misalnya, ekspresi (13) melompat ke ekspresi (2):

Seperti halnya primitif paralelisme sejak awal artikel, maka tidak ada kesepakatan tentang apa yang disebut operasi "lompatan satu arah" ini. Dalam daftar, ini JUMP TO
, tapi goto
historis berakar (seperti "pergi ke sana"), yang saya gunakan di sini.
Inilah set lengkap lompatan goto
dalam program kecil ini:

Ini tampaknya membingungkan tidak hanya untuk Anda! FLOW-MATIC mewarisi gaya pemrograman berbasis jumping ini langsung dari assembler. Ini kuat, sangat dekat dengan bagaimana perangkat keras komputer sebenarnya bekerja, tetapi sangat sulit untuk bekerja secara langsung dengannya. Bola panah ini adalah alasan untuk penemuan istilah "kode spaghetti."
Tetapi mengapa goto
menyebabkan masalah seperti itu? Mengapa beberapa pernyataan kontrol baik dan lainnya tidak? Bagaimana cara memilih yang baik? Pada saat itu benar-benar tidak dapat dipahami, dan jika Anda tidak mengerti masalahnya, sulit untuk dipecahkan.
Apa yang go
Mari kita menyimpang dari cerita kita. Semua orang tahu goto
itu buruk, tetapi apa hubungannya dengan asinkron? Lihatlah ekspresi go
terkenal dari Golang, yang digunakan untuk menelurkan "goroutine" (aliran ringan) baru:
// Golang go myfunc();
Apakah mungkin menggambar diagram aliran eksekusi? Ini sedikit berbeda dari diagram di atas, karena di sini aliran dibagi. Mari menggambar seperti ini:

Warna-warna di sini dimaksudkan untuk menunjukkan bahwa kedua jalur dipilih. Dari sudut pandang induk goroutine (garis hijau) - aliran kontrol dijalankan secara berurutan: dimulai dari atas dan kemudian segera turun. Sementara itu, dari sudut pandang fungsi keturunan (garis lilac), aliran datang dari atas dan kemudian melompat ke tubuh myfunc
. Tidak seperti panggilan fungsi biasa, ada lompatan satu arah - mulai myfunc
kita beralih ke tumpukan yang sama sekali baru dan runtime segera lupa dari mana kita berasal.
Rupanya maksud saya tumpukan panggilan
Tetapi ini tidak hanya berlaku untuk Golang. Diagram ini berlaku untuk semua primitif (kontrol) yang tercantum di awal artikel:
- Pustaka penjelajahan biasanya mengembalikan beberapa jenis objek kontrol yang akan memungkinkan mereka untuk bergabung dengan utas nanti - tetapi ini adalah operasi independen yang tidak diketahui oleh bahasa itu sendiri. Primitif untuk membuat utas baru memiliki diagram yang ditunjukkan di atas.
- Pendaftaran panggilan balik secara semantik setara dengan membuat utas latar belakang (meskipun jelas bahwa implementasinya berbeda), yang:
a) diblokir sampai suatu peristiwa terjadi, dan kemudian
b) meluncurkan fungsi panggilan balik
Jadi, dalam hal operator kontrol tingkat tinggi, registrasi callback adalah ekspresi yang identik dengan go
. - Dengan
Futures
and Promises
hal yang sama - ketika Anda menjalankan fungsi dan mengembalikan Promise
, itu berarti ia berencana untuk bekerja di latar belakang dan mengembalikan objek kontrol untuk mendapatkan hasilnya nanti (jika Anda mau). Dari sudut pandang semantik manajemen, itu sama dengan menciptakan aliran. Setelah itu, Anda meneruskan panggilan balik ke Promis dan kemudian seperti pada paragraf sebelumnya.
Pola yang sama ini menunjukkan dirinya dalam banyak bentuk - kesamaan utama adalah bahwa dalam semua kasus ini aliran kontrol dibagi - lompatan dibuat ke utas baru, tetapi orang tua kembali ke orang yang menyebutnya. Mengetahui apa yang harus dilihat, Anda akan melihatnya di mana-mana! Ini adalah permainan yang menarik (setidaknya untuk beberapa tipe orang)!
Namun, itu mengganggu saya bahwa tidak ada nama standar untuk kategori pernyataan kontrol ini. Saya menggunakan ungkapan "go" untuk memanggil mereka, sama seperti "goto" telah menjadi istilah umum untuk semua ekspresi goto
. Kenapa go
? Salah satu alasannya adalah bahwa Golang memberi kita contoh sintaksis yang sangat bersih. Dan yang lainnya adalah:

Perhatikan kesamaannya? Itu benar - go
adalah salah satu bentuk goto
.
Program asinkron terkenal karena sulitnya menulis dan menganalisis. Serta program berdasarkan goto
. Masalah yang disebabkan oleh goto
sebagian besar diselesaikan dalam bahasa modern. Jika kita mempelajari cara memperbaiki goto
, akankah ini membantu untuk membuat API asinkron yang lebih nyaman? Ayo cari tahu!
Apa yang terjadi dengan goto
?
Jadi apa yang salah dengan goto
yang menyebabkan begitu banyak masalah? Pada akhir 60-an, Edsger Wee Dijkstra menulis beberapa karya yang sekarang dikenal yang membantu untuk memahami ini dengan lebih jelas: Argumen terhadap operator goto dan Catatan tentang pemrograman struktural .
goto
menghancurkan abstraksi
Dalam karya-karya ini, Dijkstra khawatir tentang bagaimana kita menulis program yang tidak sepele dan memastikan kebenarannya. Ada banyak poin menarik. Misalnya, Anda mungkin pernah mendengar frasa ini:
Program pengujian dapat menunjukkan adanya kesalahan, tetapi tidak pernah ada.
Ya, ini dari Catatan Pemrograman Struktural . Tetapi perhatian utamanya adalah abstraksi . Dia ingin menulis program terlalu besar untuk menahan mereka di kepala mereka. Untuk melakukan ini, Anda harus memperlakukan bagian-bagian program sebagai kotak hitam - misalnya, Anda melihat program ini dengan Python:
print("Hello World!")
dan Anda tidak perlu tahu semua detail tentang cara print
(pemformatan garis, buffering, perbedaan lintas platform, dll.). Yang perlu Anda ketahui adalah bahwa print
entah bagaimana mencetak teks yang Anda print
, dan Anda dapat berkonsentrasi pada apa yang ingin Anda lakukan dalam potongan kode ini. Dijkstra ingin bahasa mendukung jenis abstraksi ini.
Pada titik ini, sintaksis blok diciptakan dan bahasa seperti ALGOL terakumulasi ~ 5 jenis pernyataan kontrol yang berbeda: mereka masih memiliki untaian eksekusi dan goto
:

Dan juga memperoleh kondisi, siklus, dan panggilan fungsi:

Anda dapat menerapkan konstruksi tingkat tinggi ini menggunakan goto
, dan ini adalah cara orang berpikir tentang mereka sebelumnya: sebagai jalan pintas yang nyaman. Tetapi Dijkstra menunjukkan perbedaan besar antara goto
dan operator kontrol lainnya. Untuk segalanya kecuali goto
, utas eksekusi
- berasal dari atas => [sesuatu terjadi] => aliran datang dari bawah
Kita dapat menyebutnya "aturan kotak hitam" - jika struktur kontrol (operator kontrol) memiliki formulir ini, maka dalam situasi di mana Anda tidak tertarik dengan detail di dalamnya, Anda dapat mengabaikan bagian "sesuatu terjadi" dan memperlakukan blok seperti urutan berurutan reguler. tim. Bahkan lebih baik, ini berlaku untuk semua kode yang terdiri dari blok-blok ini. Ketika saya melihat:
print("Hello World!")
Saya tidak perlu membaca sumber print
dan semua dependensinya untuk memahami ke mana utas eksekusi akan pergi. Mungkin di dalam print
ada loop, dan di dalamnya ada kondisi di mana ada panggilan ke fungsi lain ... itu semua tidak penting - saya tahu bahwa utas akan pergi untuk print
, fungsi akan melakukan tugasnya, dan akhirnya utas akan kembali ke kode yang saya Saya baca.
Tetapi jika Anda memiliki bahasa dengan goto
- bahasa di mana fungsi dan segala sesuatu dibangun atas dasar goto
, dan goto
dapat melompat di mana saja, kapan saja - maka struktur ini bukanlah kotak hitam sama sekali! Jika Anda memiliki fungsi dengan loop, di dalamnya ada kondisi, dan di dalamnya ada goto
... maka goto
ini dapat melewati eksekusi di mana saja. Mungkin kendali akan tiba-tiba kembali sepenuhnya dari fungsi lain yang bahkan belum Anda panggil! Kamu tidak tahu!
Dan itu menghancurkan abstraksi - fungsi apa pun dapat memiliki goto
potensial di dalam, dan satu-satunya cara untuk mengetahui apakah ini masalahnya adalah dengan mengingat semua kode sumber sistem Anda. Setelah bahasa goto
, Anda tidak dapat memprediksi alur eksekusi. Itu sebabnya goto
mengarah ke kode spageti.
Dan begitu Dijkstra memahami masalahnya, dia bisa menyelesaikannya. Berikut ini adalah asumsi revolusionernya - kita seharusnya tidak memikirkan kondisi / loop / fungsi memanggil singkatan untuk goto
, tetapi sebagai primitif mendasar dengan hak-hak kita - dan kita harus sepenuhnya menghilangkan goto
dari bahasa kita.
Dari 2018, ini tampak cukup jelas. Tetapi bagaimana para programmer bereaksi ketika Anda mencoba mengambil mainan mereka yang tidak aman? Pada tahun 1969, proposal Dijkstra tampak sangat meragukan. Donald Knuth membela goto
. Orang-orang yang menjadi ahli dalam coding dengan goto
benar marah terhadap harus belajar kembali bagaimana mengekspresikan ide-ide mereka dalam istilah baru yang lebih ketat. Dan tentu saja, dibutuhkan untuk membuat bahasa yang benar-benar baru.
Akibatnya, bahasa modern sedikit kurang ketat daripada kata-kata asli Dijkstra.

Kiri: goto
tradisional. Kanan: Domestikasi goto
, seperti dalam C, C #, Golang, dll. Kegagalan untuk melewati batas-batas fungsi berarti bahwa ia masih bisa mengencingi sepatu Anda, tetapi tidak mungkin membuat Anda terpisah.
Mereka memungkinkan Anda untuk melompat tingkat pernyataan kontrol struktural menggunakan pernyataan break
, continue
, atau return
. Tetapi pada tingkat dasar, mereka semua dibangun di sekitar ide Dijkstra dan dapat mengganggu aliran eksekusi berurutan dengan cara yang sangat terbatas. Secara khusus, fungsi - alat dasar untuk membungkus utas eksekusi dalam kotak hitam - tidak bisa dihancurkan. Anda tidak dapat menjalankan perintah break
dari satu fungsi ke fungsi lain dan return
tidak dapat mengembalikan Anda lebih jauh dari fungsi saat ini. Tidak ada manipulasi utas eksekusi di dalam fungsi yang akan memengaruhi fungsi lain.
Dan bahasa yang melestarikan operator goto
(C, C #, Golang, ...) sangat membatasinya. Minimal, mereka tidak memungkinkan Anda untuk melompat dari tubuh satu fungsi ke fungsi lainnya. Jika Anda tidak menggunakan Assembler [2], goto
klasik dan tidak terbatas adalah sesuatu dari masa lalu. Dijkstra menang.
Dunia baru yang berani tanpa goto
Sesuatu yang menarik terjadi dengan hilangnya goto
- pembuat bahasa dapat mulai menambahkan fitur baru berdasarkan alur eksekusi terstruktur.
Misalnya, Python memiliki sintaks keren untuk secara otomatis menghapus sumber daya - manajer konteks . Anda dapat menulis:
dan ini memastikan bahwa file akan dibuka pada saat runtime some code
tetapi setelah itu - segera ditutup. Sebagian besar bahasa modern memiliki padanan ( RAII , using
, coba-dengan-sumber daya, defer
, ...). Dan mereka semua beranggapan bahwa aliran kontrol teratur. Dan apa yang terjadi jika kita melompat ke blok with
menggunakan goto
? Apakah file terbuka atau tidak? Dan jika kita melompat keluar dari sana daripada pergi seperti biasa?
setelah kode di dalam blok selesai, with
memulai metode __exit__()
yang menutup sumber daya terbuka, seperti file dan koneksi.
Apakah file akan ditutup? Dalam goto
, manajer konteks tidak bekerja dengan jelas.
Masalah yang sama dengan penanganan kesalahan - ketika terjadi kesalahan, apa yang harus dilakukan kode? Seringkali - kirim deskripsi kesalahan hingga tumpukan (panggilan) ke kode panggilan dan biarkan memutuskan apa yang harus dilakukan. Bahasa modern memiliki konstruksi khusus untuk ini, seperti Pengecualian atau bentuk peningkatan kesalahan otomatis lainnya . Tetapi bantuan ini hanya tersedia jika bahasa memiliki tumpukan panggilan dan konsep "panggilan" yang kuat. Ingat spageti dalam contoh aliran dalam contoh FLOW-MATIC dan bayangkan pengecualian yang dilemparkan di tengah. Di mana itu bahkan bisa datang?
Tidak ada lagi goto
Jadi, goto
tradisional - yang mengabaikan batas fungsi - buruk bukan hanya karena sulit digunakan dengan benar. Kalau saja ini, goto
bisa tinggal - banyak konstruksi bahasa yang buruk tetap.
Tetapi bahkan fitur yang sangat goto
dalam bahasa membuat segalanya lebih rumit. Perpustakaan pihak ketiga tidak dapat dianggap sebagai kotak hitam - tanpa mengetahui sumbernya, Anda tidak dapat mengetahui fungsi mana yang normal dan yang secara tak terduga mengontrol aliran eksekusi. Ini adalah hambatan utama untuk memprediksi perilaku kode lokal. Fitur hebat seperti manajer konteks dan pop-up kesalahan otomatis juga hilang. Lebih baik menghapus goto
sekaligus, demi operator kontrol yang mendukung aturan kotak hitam.
Tentang bahaya ekspresi seperti "Pergi"
Jadi, kami melihat cerita goto
. Tetapi apakah itu berlaku untuk operator go
? Baiklah ... semuanya! Analogi ini sangat akurat.
pergi ekspresi mematahkan abstraksi.
Ingat bagaimana kami mengatakan bahwa jika bahasa mengizinkan goto
, maka fungsi apa pun dapat menyembunyikan goto
itu sendiri? Dalam sebagian besar kerangka kerja tidak sinkron, ekspresi go
mengarah ke masalah yang sama - fungsi apa pun mungkin (atau mungkin tidak) menjalankan tugas di latar belakang. Sepertinya fungsi telah mengembalikan kontrol, tetapi apakah masih berfungsi di latar belakang? Dan tidak ada cara untuk mengetahuinya tanpa membaca sumber fungsi dan semua yang dipanggil. Dan kapan itu akan berakhir? Sulit dikatakan. Jika Anda memiliki analognya, maka fungsinya bukan lagi kotak hitam yang menghargai aliran eksekusi. Dalam artikel pertama saya tentang API asinkron , saya menyebutnya "pelanggaran sebab-akibat" dan menemukan bahwa ini adalah penyebab utama banyak masalah nyata dalam program yang menggunakan asyncio
dan Twisted, seperti masalah kontrol aliran, masalah dengan shutdown yang tepat, dll.
Ini mengacu pada kontrol aliran data yang masuk dan keluar dari program. Sebagai contoh, program menerima data pada kecepatan 3MB / s, dan meninggalkan pada kecepatan 1MB / s, dan karenanya program mengkonsumsi lebih banyak memori, lihat artikel lain oleh penulis
go-expressions memecah pembersihan otomatis sumber daya terbuka.
Mari kita lihat contoh with
pernyataan lagi:
Sebelumnya kami mengatakan bahwa kami "dijamin" bahwa file tersebut akan terbuka ketika some code
berfungsi, dan ditutup setelahnya. Tetapi bagaimana jika some code
memulai tugas latar belakang? : , , with
, with
, , , . , ; , , some code
.
, , - , , .
, Python threading
β , , β , with
, , , ( ). , . , .
go- .
, , (exceptions), . " ". , . , , . , , β¦ , . , - . ( , , " - " β ; .) Rust β , , - β . (thread) , Rust .
, , join , errbacks Twisted Promise.catch Javascript . , , . , Traceback . Promise.catch
.
, .
go
, goto
, go- β , , , . , goto
, , go
.
, , ! :
, Trio .
go
: , , , . , , :

, , , " " .
? " " ,
) , , ( ),
) , .
. , - . , .. [3]
: , , , "" , . Trio , async with
:

, as nursery
nursery
. nursery.start_soon()
, () : myfunc
anotherfunc
. . , , () , , .

, , β , , . , .
, .
:

, . Inilah beberapa di antaranya:
.
go- β , , , . β , , . , , .
.
, . :
run_concurrently([myfunc, anotherfunc])
async.gather Python, Promise.all Javascript, ..
, , , . , accept
, .
accept
Trio:
async with trio.open_nursery() as nursery: while True: incoming_connection = await server_socket.accept() nursery.start_soon(connection_handler, incoming_connection)
, , run_concurrently
. , run_concurrently
β , , run_concurrently
, .
.
. , , ? : . , async with open_nursery()
nursery.start_soon()
, β [4], , , . , , .
, , " ", :
, .
, , go-, .
, .
, - . , , . :
async with my_supervisor_library.open_supervisor() as nursery_alike: nursery_alike.start_soon(...)
, , . .
Trio , asyncio
: start_soon()
, Future
( , Future
). , ( , Trio Future
!), .
, , .
, , β β .
Trio, . , , " " ( ), Cancelled
. , , β - , " ", , .. , , . , , , .
.
" ", with
. , with
, .
.
, , . .
Trio, , β¦ - . , . , β " " β , myfunc
anotherfunc
, . , , .
, : (re-raise) , . ,
" " , , , , , .
, , . ?
β ( ) , . , , , , .
, , - ( task cancellation ). C# Golang, β .
go
goto
, with
; go
- . Sebagai contoh:
- , , , . ( : - )
- β Python ,
ctrl-C
( ). , .
, . ?
β¦ : ! , , . , , , break
continue
.
, . β , 1970 , goto
.
. (Knuth, 1974, .275):
, goto
, , " " goto
. goto
! , , goto
, . , , . , β , β "goto" .
: . , , . , , . , , .
, Happy Eyeballs ( RFC 8305 ), TCP . , β , , . Twisted β 600 Python . 15 . , , , . , , . , . ? . .
Kesimpulan
β go
, , , Futures
, Promises
,β¦ β goto
, . goto
, -- goto
, . , , ; , . , goto
, .
, , ( CTRL+C
) , .
, , , , β , goto
. FLOW-MATIC , , - . , , Trio , , .
Komentar
Trio .
:
Trio : https://trio.discourse.group/
Ucapan Terima Kasih
Graydon Hoare, Quentin Pradet, and Hynek Schlawack . , , .
berez .
: FLOW-MATIC (PDF), .
Wolves in Action, Martin Pannier, CC-BY-SA 2.0 , .
, Daniel Borker, CC0 public domain dedication .
[2] WebAssembly , goto
: ,
[3] , , , , :
The "parallel composition" operator in Cooperating/Communicating Sequential Processes and Occam, the fork/join model, Erlang supervisors, Martin SΓΊstrik's libdill , crossbeam::scope / rayon::scope Rust. golang.org/x/sync/errgroup github.com/oklog/run Golang.
, - .
[4] start_soon()
, , start_soon
, , , . , .
Nathaniel J. Smith , Ph.D., UC Berkeley numpy
, Python . Nathaniel .
:
, , , Haskell , , .
( , 0xd34df00d , ) , ( Happy Eyeballs ), .
, Trio ? Haskell Golang ?
: