Cara menggunakan ValueTask dalam C #

Pengaturcaraan tak segerak telah lama digunakan. Dalam beberapa tahun kebelakangan ini, kata kunci ini menjadi lebih kuat dengan memperkenalkan kata kunci async dan menunggu. Anda boleh memanfaatkan pengaturcaraan tidak segerak untuk meningkatkan daya tindak dan aplikasi anda.

Jenis pengembalian yang disyorkan bagi kaedah tidak segerak di C # adalah Task. Anda harus mengembalikan Tugasan jika anda ingin menulis kaedah tidak segerak yang mengembalikan nilai. Sekiranya anda ingin menulis pengendali acara, anda boleh membatalkan kekosongan sebagai gantinya. Sehingga C # 7.0 kaedah tidak segerak dapat mengembalikan Tugas, Tugas, atau batal. Bermula dengan C # 7.0, kaedah tidak segerak juga dapat mengembalikan ValueTask (tersedia sebagai sebahagian daripada pakej System.Threading.Tasks.Extensions) atau ValueTask. Artikel ini membentangkan perbincangan tentang bagaimana kita dapat bekerja dengan ValueTask di C #.

Untuk bekerja dengan contoh kod yang disediakan dalam artikel ini, anda harus memasang Visual Studio 2019 di sistem anda. Sekiranya anda belum mempunyai salinannya, anda boleh memuat turun Visual Studio 2019 di sini.

Buat projek aplikasi konsol .NET Core di Visual Studio

Pertama, mari buat projek aplikasi konsol .NET Core di Visual Studio. Dengan mengandaikan Visual Studio 2019 dipasang di sistem anda, ikuti langkah-langkah yang digariskan di bawah untuk membuat projek aplikasi konsol .NET Core baru di Visual Studio.

  1. Lancarkan ID Studio Visual.
  2. Klik pada "Buat projek baru."
  3. Di tetingkap "Buat projek baru", pilih "Aplikasi Konsol (.NET Core)" dari senarai templat yang dipaparkan.
  4. Klik Seterusnya.
  5. Di tetingkap "Konfigurasikan projek baru anda" yang ditunjukkan di sebelah, tentukan nama dan lokasi untuk projek baru.
  6. Klik Buat.

Ini akan membuat projek aplikasi konsol .NET Core yang baru di Visual Studio 2019. Kami akan menggunakan projek ini untuk menggambarkan penggunaan ValueTask di bahagian seterusnya artikel ini.

Mengapa saya mesti menggunakan ValueTask?

Tugas mewakili keadaan beberapa operasi, iaitu, sama ada operasi selesai, dibatalkan, dan sebagainya. Kaedah tidak segerak dapat mengembalikan Task atau ValueTask.

Sekarang, kerana Task adalah jenis rujukan, mengembalikan objek Task dari kaedah asynchronous menyiratkan peruntukan objek di timbunan terkelola setiap kali kaedah dipanggil. Oleh itu, satu peringatan dalam menggunakan Task adalah anda perlu memperuntukkan memori di timbunan terkelola setiap kali anda mengembalikan objek Task dari kaedah anda. Sekiranya hasil operasi yang dilakukan dengan kaedah anda tersedia dengan segera atau selesai secara serentak, peruntukan ini tidak diperlukan dan oleh itu menjadi mahal.

Di sinilah ValueTask datang untuk menyelamatkan. ValueTask memberikan dua faedah utama. Pertama, ValueTask meningkatkan prestasi kerana tidak memerlukan peruntukan timbunan, dan kedua, mudah dan fleksibel untuk dilaksanakan. Dengan mengembalikan ValueTask dan bukannya Task dari kaedah tidak segerak apabila hasilnya segera tersedia, anda dapat mengelakkan overhead peruntukan yang tidak perlu kerana "T" di sini mewakili struktur dan struktur di C # adalah jenis nilai (berbeza dengan "T" dalam Task, yang mewakili kelas).

Task dan ValueTask mewakili dua jenis utama "ditunggu" di C #. Perhatikan bahawa anda tidak dapat menyekat ValueTask. Sekiranya anda perlu menyekat anda harus menukar ValueTask ke Task menggunakan kaedah AsTask dan kemudian blok pada objek Task rujukan itu.

Perhatikan juga bahawa setiap ValueTask boleh dimakan sekali sahaja. Di sini kata "consume" menyiratkan bahawa ValueTask dapat menunggu (menunggu) operasi secara asinkron untuk menyelesaikan atau memanfaatkan AsTask untuk menukar ValueTask menjadi Task. Walau bagaimanapun, ValueTask hanya boleh digunakan sekali, selepas itu ValueTask harus diabaikan.

Contoh ValueTask dalam C #

Katakan anda mempunyai kaedah tidak segerak yang mengembalikan Tugasan. Anda mungkin memanfaatkan Task.FromResult untuk membuat objek Task seperti yang ditunjukkan dalam coretan kod yang diberikan di bawah.

Tugas awam GetCustomerIdAsync ()

{

    mengembalikan Tugas.FromResult (1);

}

Coretan kod di atas tidak membuat sihir mesin keadaan async keseluruhan tetapi ia memperuntukkan objek Tugas di timbunan terurus. Untuk mengelakkan peruntukan ini, anda mungkin ingin memanfaatkan ValueTask seperti yang ditunjukkan dalam coretan kod yang diberikan di bawah.

nilai awam Tugas GetCustomerIdAsync ()

{

    mengembalikan ValueTask baru (1);

}

Coretan kod berikut menggambarkan pelaksanaan ValueTask segerak.

 IRepository antara muka awam

    {

        ValueTask GetData ();

    }

Kelas Repositori memperluas antara muka IRepository dan menerapkan kaedahnya seperti yang ditunjukkan di bawah.

    repositori kelas awam: IRepository

    {

        ValueTask GetData awam ()

        {

            nilai var = lalai (T);

            mengembalikan ValueTask (nilai) baru;

        }

    }

Inilah cara anda boleh memanggil kaedah GetData dari kaedah Utama.

kekosongan statik Utama (string [] args)

        {

            Repositori IRepository = Repositori baru ();

            var result = repository.GetData ();

            jika (hasilnya. Selesai)

                 Console.WriteLine ("Operasi selesai ...");

            yang lain

                Console.WriteLine ("Operasi tidak lengkap ...");

            Konsol.ReadKey ();

        }

Mari sekarang tambahkan kaedah lain ke repositori kami, kali ini kaedah tak segerak bernama GetDataAsync. Inilah rupa antara muka IRepository yang diubah suai.

IRepository antara muka awam

    {

        ValueTask GetData ();

        ValueTask GetDataAsync ();

    }

Kaedah GetDataAsync dilaksanakan oleh kelas Repositori seperti yang ditunjukkan dalam coretan kod yang diberikan di bawah.

    repositori kelas awam: IRepository

    {

        ValueTask GetData awam ()

        {

            nilai var = lalai (T);

            mengembalikan ValueTask (nilai) baru;

        }

        async awamTugasan GetDataAsync ()

        {

            nilai var = lalai (T);

            tunggu Task.Delay (100);

            nilai pulangan;

        }

    }

Bilakah saya harus menggunakan ValueTask dalam C #?

Walaupun faedah yang diberikan oleh ValueTask, terdapat pertukaran tertentu untuk menggunakan ValueTask sebagai pengganti Tugas. ValueTask adalah jenis nilai dengan dua medan, sedangkan Tugas adalah jenis rujukan dengan satu bidang. Oleh itu, menggunakan ValueTask bermaksud bekerja dengan lebih banyak data kerana kaedah panggilan akan mengembalikan dua bidang data sebagai pengganti satu. Juga, jika anda menunggu kaedah yang mengembalikan ValueTask, mesin keadaan untuk kaedah tidak segerak juga akan lebih besar - kerana ia harus menampung struktur yang mengandungi dua bidang sebagai ganti satu rujukan dalam kes Tugas.

Selanjutnya, jika pengguna kaedah tidak segerak menggunakan Task.WhenAll atau Task.WhenAny, menggunakan ValueTask sebagai jenis pengembalian dalam kaedah tidak segerak mungkin menjadi mahal. Ini kerana anda perlu menukar ValueTask ke Task menggunakan kaedah AsTask, yang akan dikenakan peruntukan yang dapat dengan mudah dihindari jika Task cache telah digunakan di tempat pertama.

Inilah peraturan ibu jari. Gunakan Tugas apabila anda mempunyai sekeping kod yang akan selalu tidak segerak, iaitu apabila operasi tidak akan selesai dengan segera. Manfaatkan ValueTask apabila hasil operasi asinkron sudah tersedia atau ketika anda sudah mempunyai hasil cache. Bagaimanapun, anda harus melakukan analisis prestasi yang diperlukan sebelum mempertimbangkan ValueTask.

Cara melakukan lebih banyak perkara di C #:

  • Cara menggunakan kebolehubahan dalam C
  • Cara menggunakan const, hanya baca, dan statik di C #
  • Cara menggunakan anotasi data di C #
  • Cara bekerja dengan GUID di C # 8
  • Bilakah menggunakan kelas abstrak vs antara muka dalam C #
  • Cara bekerja dengan AutoMapper di C #
  • Cara menggunakan ungkapan lambda dalam C #
  • Cara bekerjasama dengan delegasi Action, Func, dan Predicate di C #
  • Cara bekerja dengan perwakilan di C #
  • Cara melaksanakan pembalak sederhana di C #
  • Cara bekerja dengan atribut di C #
  • Cara bekerja dengan log4net di C #
  • Cara melaksanakan corak reka bentuk repositori di C #
  • Cara bekerja dengan refleksi di C #
  • Cara bekerja dengan pemantau sistem fail di C #
  • Cara melakukan inisial malas di C #
  • Cara bekerja dengan MSMQ di C #
  • Cara bekerja dengan kaedah peluasan di C #
  • Bagaimana untuk kami ungkapan lambda dalam C #
  • Bilakah menggunakan kata kunci tidak stabil dalam C #
  • Cara menggunakan kata kunci hasil dalam C #
  • Cara melaksanakan polimorfisme dalam C #
  • Bagaimana membina penjadual tugas anda sendiri di C #
  • Cara bekerja dengan RabbitMQ di C #
  • Cara bekerja dengan tuple di C #
  • Meneroka kaedah maya dan abstrak dalam C #
  • Cara menggunakan Dapper ORM di C #
  • Cara menggunakan corak reka bentuk flyweight di C #