Kapan pun Anda perlu melakukan tindakan di server jarak jauh, program Anda membuat permintaan, mengirimkannya, lalu menunggu tanggapan. Saya akan menggunakan SaveChanges()dan SaveChangesAsync()sebagai contoh tetapi hal yang sama berlaku untuk Find()dan FindAsync().
Katakanlah Anda memiliki daftar myList100+ item yang perlu Anda tambahkan ke database Anda. Untuk memasukkannya, fungsi Anda akan terlihat seperti ini:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
Pertama Anda membuat instance MyEDM, menambahkan daftar myListke tabel MyTable, lalu memanggil SaveChanges()untuk mempertahankan perubahan ke database. Ini berfungsi seperti yang Anda inginkan, record dikomit, tetapi program Anda tidak dapat melakukan apa pun sampai komit selesai. Ini bisa memakan waktu lama tergantung pada apa yang Anda lakukan. Jika Anda melakukan perubahan pada record, entitas harus mengkomitnya satu per satu (saya pernah menyimpan membutuhkan waktu 2 menit untuk update)!
Untuk mengatasi masalah ini, Anda dapat melakukan salah satu dari dua hal. Yang pertama adalah Anda dapat memulai utas baru untuk menangani penyisipan. Meskipun ini akan membebaskan utas panggilan untuk terus mengeksekusi, Anda membuat utas baru yang hanya akan duduk di sana dan menunggu. Tidak perlu biaya tambahan itu, dan inilah yang async awaitdipecahkan oleh polanya.
Untuk pengoperasian I / O, awaitcepatlah menjadi sahabat Anda. Mengambil bagian kode dari atas, kita dapat memodifikasinya menjadi:
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
Ini adalah perubahan yang sangat kecil, tetapi ada efek yang sangat besar pada efisiensi dan kinerja kode Anda. Lalu apa yang terjadi? Awal kodenya sama, Anda membuat instance MyEDMdan menambahkan myListke MyTable. Tetapi ketika Anda memanggil await context.SaveChangesAsync(), eksekusi kode kembali ke fungsi panggilan! Jadi, saat Anda menunggu semua record tersebut dijalankan, kode Anda dapat terus dieksekusi. Katakanlah fungsi yang berisi kode di atas memiliki tanda tangan public async Task SaveRecords(List<MyTable> saveList), fungsi pemanggilan bisa terlihat seperti ini:
public async Task MyCallingFunction()
{
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++){
Console.WriteLine("Continuing to execute!");
}
await saveTask;
Console.Log("Function Complete");
}
Mengapa Anda memiliki fungsi seperti ini, saya tidak tahu, tetapi apa yang dihasilkannya menunjukkan cara async awaitkerjanya. Pertama, mari kita bahas apa yang terjadi.
Eksekusi masuk MyCallingFunction, Function Startinglalu Save Startingditulis ke konsol, lalu fungsi SaveChangesAsync()dipanggil. Pada titik ini, eksekusi kembali ke MyCallingFunctiondan memasuki penulisan loop for 'Continuing to Execute' hingga 1000 kali. Setelah SaveChangesAsync()selesai, eksekusi kembali ke SaveRecordsfungsi, menulis Save Completeke konsol. Setelah semuanya SaveRecordsselesai, eksekusi akan dilanjutkan MyCallingFunctionjika sudah SaveChangesAsync()selesai. Bingung? Berikut adalah contoh keluarannya:
Fungsi Mulai
Simpan Mulai
Terus mengeksekusi!
Terus mengeksekusi!
Terus mengeksekusi!
Terus mengeksekusi!
Terus mengeksekusi!
....
Terus mengeksekusi!
Simpan Selesai!
Terus mengeksekusi!
Terus mengeksekusi!
Terus mengeksekusi!
....
Terus mengeksekusi!
Fungsi Selesai!
Atau mungkin:
Fungsi Mulai
Simpan Mulai
Terus mengeksekusi!
Terus mengeksekusi!
Simpan Selesai!
Terus mengeksekusi!
Terus mengeksekusi!
Terus mengeksekusi!
....
Terus mengeksekusi!
Fungsi Selesai!
Itulah keindahannya async await, kode Anda dapat terus berjalan saat Anda menunggu sesuatu untuk diselesaikan. Pada kenyataannya, Anda akan memiliki fungsi yang lebih seperti ini sebagai fungsi panggilan Anda:
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
}
Di sini, Anda memiliki empat fungsi penyimpanan catatan yang berbeda yang berjalan pada saat bersamaan . MyCallingFunctionakan menyelesaikan penggunaan lebih cepat async awaitdaripada jika SaveRecordsfungsi individu dipanggil secara seri.
Satu hal yang belum saya singgung adalah awaitkata kunci. Apa yang dilakukannya adalah menghentikan fungsi saat ini dari eksekusi hingga apa pun yang TaskAnda tunggu selesai. Jadi dalam kasus aslinya MyCallingFunction, baris Function Completetidak akan ditulis ke konsol sampai SaveRecordsfungsinya selesai.
Singkat cerita, jika Anda memiliki opsi untuk menggunakan async await, Anda harus melakukannya karena akan sangat meningkatkan kinerja aplikasi Anda.