Saya pikir mereka pada dasarnya adalah hal yang sama - menulis program yang membagi tugas antara prosesor (pada mesin yang memiliki 2+ prosesor). Lalu saya membaca ini , yang mengatakan:
Metode Async dimaksudkan sebagai operasi non-pemblokiran. Ekspresi menunggu dalam metode async tidak memblokir utas saat ini sementara tugas yang ditunggu-tunggu sedang berjalan. Sebaliknya, ekspresi mendaftar sisa metode sebagai kelanjutan dan mengembalikan kontrol ke pemanggil metode async.
Async dan menunggu kata kunci tidak menyebabkan utas tambahan dibuat. Metode Async tidak memerlukan multithreading karena metode async tidak berjalan pada utasnya sendiri. Metode ini berjalan pada konteks sinkronisasi saat ini dan menggunakan waktu pada utas hanya ketika metode ini aktif. Anda bisa menggunakan Task.Run untuk memindahkan pekerjaan yang terikat CPU ke utas latar belakang, tetapi utas latar tidak membantu proses yang hanya menunggu hasil tersedia.
dan saya bertanya-tanya apakah seseorang dapat menerjemahkannya ke bahasa Inggris untuk saya. Tampaknya menarik perbedaan antara asyncronicity (apakah itu sebuah kata?) Dan threading dan menyiratkan bahwa Anda dapat memiliki program yang memiliki tugas-tugas yang tidak sinkron tetapi tidak multithreading.
Sekarang saya mengerti ide tugas asinkron seperti contoh pada hal. 467 dari Jon Skeet's C # In Depth, Edisi Ketiga
async void DisplayWebsiteLength ( object sender, EventArgs e )
{
label.Text = "Fetching ...";
using ( HttpClient client = new HttpClient() )
{
Task<string> task = client.GetStringAsync("http://csharpindepth.com");
string text = await task;
label.Text = text.Length.ToString();
}
}
Kata async
kunci berarti " Fungsi ini, kapan pun dipanggil, tidak akan dipanggil dalam konteks di mana penyelesaiannya diperlukan untuk semua setelah panggilannya dipanggil."
Dengan kata lain, menulis itu di tengah-tengah beberapa tugas
int x = 5;
DisplayWebsiteLength();
double y = Math.Pow((double)x,2000.0);
, Karena DisplayWebsiteLength()
tidak ada hubungannya dengan x
atau y
, akan menyebabkan DisplayWebsiteLength()
dieksekusi "di latar belakang", seperti
processor 1 | processor 2
-------------------------------------------------------------------
int x = 5; | DisplayWebsiteLength()
double y = Math.Pow((double)x,2000.0); |
Jelas itu contoh yang bodoh, tetapi apakah saya benar atau saya benar-benar bingung atau apa?
(Juga, saya bingung tentang mengapa sender
dan e
tidak pernah digunakan dalam tubuh fungsi di atas.)
sumber
sender
dane
menyarankan ini sebenarnya adalah pengendali acara - cukup banyak satu-satunya tempatasync void
yang diinginkan. Kemungkinan besar, ini disebut pada klik tombol atau sesuatu seperti itu - hasilnya adalah bahwa tindakan ini terjadi sepenuhnya secara tidak sinkron sehubungan dengan sisa aplikasi. Tapi itu semua masih dalam satu utas - utas UI (dengan sepotong kecil waktu pada utas IOCP yang memposting panggilan balik ke utas UI).DisplayWebsiteLength
contoh kode: Anda tidak boleh menggunakanHttpClient
dalamusing
pernyataan - Di bawah beban yang berat, kode dapat menghabiskan jumlah soket yang tersedia yang mengakibatkan kesalahan SocketException. Info lebih lanjut tentang Instansiasi yang Tidak Benar .Jawaban:
Kesalahpahaman Anda sangat umum. Banyak orang diajari bahwa multithreading dan asynchrony adalah hal yang sama, tetapi sebenarnya tidak.
Analogi biasanya membantu. Anda sedang memasak di restoran. Pesanan datang untuk telur dan roti panggang.
Sekarang apakah masuk akal bahwa multithreading hanya satu jenis asinkron? Threading adalah tentang pekerja; asynchrony adalah tentang tugas . Dalam alur kerja multithreaded Anda menetapkan tugas kepada pekerja. Dalam alur kerja single-threaded asinkron Anda memiliki grafik tugas di mana beberapa tugas bergantung pada hasil yang lain; karena setiap tugas selesai itu memanggil kode yang menjadwalkan tugas berikutnya yang dapat dijalankan, mengingat hasil tugas yang baru saja selesai. Tapi Anda (semoga) hanya membutuhkan satu pekerja untuk melakukan semua tugas, bukan satu pekerja per tugas.
Ini akan membantu untuk menyadari bahwa banyak tugas tidak terikat prosesor. Untuk tugas-tugas yang terikat prosesor, masuk akal untuk merekrut sebanyak mungkin pekerja (utas) karena ada prosesor, tetapkan satu tugas untuk setiap pekerja, tetapkan satu prosesor untuk setiap pekerja, dan mintalah setiap prosesor melakukan pekerjaan tidak lain selain menghitung hasilnya sebagai secepat mungkin. Tetapi untuk tugas yang tidak menunggu prosesor, Anda tidak perlu menugaskan pekerja sama sekali. Anda tinggal menunggu pesan sampai bahwa hasilnya tersedia dan melakukan sesuatu yang lain saat Anda menunggu . Ketika pesan itu tiba maka Anda dapat menjadwalkan kelanjutan dari tugas yang diselesaikan sebagai hal berikutnya pada daftar tugas yang harus Anda selesaikan.
Jadi mari kita lihat contoh Jon lebih detail. Apa yang terjadi?
text
dan menjalankan sisa metode.Seperti analogi saya. Seseorang meminta Anda untuk sebuah dokumen. Anda mengirim surat untuk dokumen, dan terus melakukan pekerjaan lain. Ketika tiba di surat Anda diberi sinyal, dan ketika Anda merasa seperti itu, Anda melakukan sisa alur kerja - buka amplop, bayar biaya pengiriman, apa pun. Anda tidak perlu mempekerjakan pekerja lain untuk melakukan semua itu untuk Anda.
sumber
Javascript dalam peramban adalah contoh yang bagus dari program asinkron yang tidak memiliki utas.
Anda tidak perlu khawatir tentang beberapa keping kode yang menyentuh objek yang sama secara bersamaan: setiap fungsi akan selesai berjalan sebelum javascript lain diizinkan berjalan di halaman.
Namun, ketika melakukan sesuatu seperti permintaan AJAX, tidak ada kode yang berjalan sama sekali, sehingga javascript lain dapat merespons hal-hal seperti peristiwa klik hingga permintaan itu kembali dan memanggil panggilan balik yang terkait dengannya. Jika salah satu dari penangan acara ini masih berjalan ketika permintaan AJAX kembali, penangannya tidak akan dipanggil sampai selesai. Hanya ada satu "utas" JavaScript yang berjalan, meskipun mungkin bagi Anda untuk secara efektif menjeda hal yang Anda lakukan sampai Anda memiliki informasi yang Anda butuhkan.
Dalam aplikasi C #, hal yang sama terjadi setiap kali Anda berurusan dengan elemen UI - Anda hanya diizinkan berinteraksi dengan elemen UI saat Anda berada di utas UI. Jika pengguna mengklik tombol, dan Anda ingin merespons dengan membaca file besar dari disk, seorang programmer yang tidak berpengalaman mungkin membuat kesalahan dengan membaca file dalam event handler klik itu sendiri, yang akan menyebabkan aplikasi "membeku" sampai file selesai dimuat karena tidak diizinkan menanggapi klik, melayang, atau peristiwa terkait UI lainnya apa pun hingga utas tersebut dibebaskan.
Salah satu opsi yang mungkin digunakan oleh pemrogram untuk menghindari masalah ini adalah membuat utas baru untuk memuat file, dan kemudian memberi tahu kode utas itu bahwa ketika file dimuat, perlu menjalankan kode yang tersisa pada utas UI lagi sehingga dapat memperbarui elemen UI berdasarkan apa yang ditemukan dalam file. Sampai baru-baru ini, pendekatan ini sangat populer karena itu adalah apa yang dipermudah oleh perpustakaan C # dan bahasa, tetapi pada dasarnya lebih rumit daripada yang seharusnya.
Jika Anda berpikir tentang apa yang dilakukan CPU ketika membaca file di tingkat perangkat keras dan Sistem Operasi, itu pada dasarnya mengeluarkan instruksi untuk membaca potongan data dari disk ke dalam memori, dan mengenai sistem operasi dengan "interupsi". "Saat pembacaan selesai. Dengan kata lain, membaca dari disk (atau I / O benar-benar) adalah operasi yang asinkron secara inheren . Konsep utas menunggu I / O untuk menyelesaikan adalah abstraksi yang dibuat oleh pengembang perpustakaan untuk membuatnya lebih mudah untuk diprogram. Itu tidak perlu.
Sekarang, sebagian besar operasi I / O di .NET memiliki
...Async()
metode yang sesuai Anda dapat memanggil, yang mengembalikanTask
hampir segera. Anda dapat menambahkan panggilan balik ke iniTask
untuk menentukan kode yang ingin Anda jalankan ketika operasi asinkron selesai. Anda juga dapat menentukan utas mana yang Anda inginkan untuk menjalankan kode itu, dan Anda dapat memberikan token yang dapat diperiksa oleh operasi asinkron dari waktu ke waktu untuk melihat apakah Anda memutuskan untuk membatalkan tugas asinkron, memberikannya kesempatan untuk menghentikan kerjanya dengan cepat dan dengan anggun.Sampai
async/await
kata kunci ditambahkan, C # jauh lebih jelas tentang bagaimana kode panggilan balik dipanggil, karena panggilan balik itu dalam bentuk delegasi yang Anda kaitkan dengan tugas. Agar tetap memberi Anda manfaat menggunakan...Async()
operasi, sambil menghindari kerumitan dalam kode,async/await
abstraksi dari penciptaan delegasi tersebut. Tapi mereka masih ada di kode yang dikompilasi.Jadi Anda dapat memiliki event handler UI Anda
await
operasi I / O, membebaskan utas UI untuk melakukan hal-hal lain, dan lebih atau kurang otomatis kembali ke utas UI setelah Anda selesai membaca file - tanpa harus buat utas baru.sumber