Menggunakan ThreadPool.QueueUserWorkItem di ASP.NET dalam skenario lalu lintas tinggi

111

Saya selalu mendapat kesan bahwa menggunakan ThreadPool untuk (katakanlah tidak kritis) tugas latar belakang berumur pendek dianggap sebagai praktik terbaik, bahkan di ASP.NET, tetapi kemudian saya menemukan artikel ini yang tampaknya menyarankan sebaliknya - Argumennya adalah bahwa Anda harus meninggalkan ThreadPool untuk menangani permintaan terkait ASP.NET.

Jadi, inilah cara saya melakukan tugas asinkron kecil sejauh ini:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

Dan artikel tersebut menyarankan untuk membuat utas secara eksplisit, mirip dengan:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

Metode pertama memiliki keuntungan karena dikelola dan dibatasi, tetapi ada potensi (jika artikelnya benar) bahwa tugas latar belakang kemudian bersaing untuk mendapatkan untaian dengan penangan permintaan ASP.NET. Metode kedua membebaskan ThreadPool, tetapi dengan biaya tidak dibatasi dan dengan demikian berpotensi menggunakan terlalu banyak sumber daya.

Jadi pertanyaan saya adalah, apakah saran dalam artikel tersebut benar?

Jika situs Anda mendapatkan begitu banyak lalu lintas sehingga ThreadPool Anda semakin penuh, maka apakah lebih baik untuk keluar dari band, atau apakah ThreadPool penuh menyiratkan bahwa Anda sampai pada batas sumber daya Anda, dalam hal ini Anda seharusnya tidak mencoba memulai utas Anda sendiri?

Klarifikasi: Saya hanya bertanya dalam lingkup tugas asinkron kecil non-kritis (misalnya, pencatatan jarak jauh), bukan item pekerjaan mahal yang memerlukan proses terpisah (dalam kasus ini saya setuju Anda memerlukan solusi yang lebih kuat).

Michael Hart
sumber
Plotnya semakin tebal - Saya menemukan artikel ini ( blogs.msdn.com/nicd/archive/2007/04/16/… ), yang tidak dapat saya pecahkan kodenya. Di satu sisi, tampaknya mengatakan bahwa IIS 6.0+ selalu memproses permintaan pada utas pekerja kumpulan utas (dan bahwa versi sebelumnya mungkin melakukannya), tetapi kemudian ada ini: "Namun jika Anda menggunakan laman asinkron .NET 2.0 baru ( Async = "true") atau ThreadPool.QueueUserWorkItem (), maka bagian asinkron dari pemrosesan akan dilakukan di dalam [utas port penyelesaian]. " Bagian asinkron dari pemrosesan ?
Jeff Sternal
Satu hal lagi - ini seharusnya cukup mudah untuk diuji pada instalasi IIS 6.0+ (yang tidak saya miliki saat ini) dengan memeriksa apakah thread pekerja yang tersedia di kumpulan thread lebih rendah dari thread pekerja maksimalnya, lalu melakukan hal yang sama dalam antrian item pekerjaan.
Jeff Sternal

Jawaban:

104

Jawaban lain di sini tampaknya mengabaikan poin terpenting:

Kecuali Anda mencoba memparalelkan operasi intensif CPU untuk menyelesaikannya lebih cepat di situs dengan beban rendah, tidak ada gunanya menggunakan thread pekerja sama sekali.

Itu berlaku untuk utas gratis, yang dibuat oleh new Thread(...), dan utas pekerja di ThreadPoolyang merespons QueueUserWorkItempermintaan.

Ya, itu benar, Anda dapat membuat ThreadPoolproses ASP.NET kelaparan dengan mengantri terlalu banyak item pekerjaan. Ini akan mencegah ASP.NET memproses permintaan lebih lanjut. Informasi dalam artikel tersebut akurat dalam hal itu; kumpulan utas yang sama digunakan untuk QueueUserWorkItemjuga digunakan untuk melayani permintaan.

Tetapi jika Anda benar-benar mengantri cukup banyak item pekerjaan untuk menyebabkan kelaparan ini, maka Anda harus membuat kumpulan utas kelaparan! Jika Anda menjalankan ratusan operasi intensif CPU pada saat yang sama, apa gunanya memiliki thread pekerja lain untuk melayani permintaan ASP.NET, ketika mesin sudah kelebihan beban? Jika Anda mengalami situasi ini, Anda perlu mendesain ulang sepenuhnya!

Sebagian besar waktu saya melihat atau mendengar tentang kode multi-utas yang digunakan secara tidak tepat di ASP.NET, ini bukan untuk mengantri pekerjaan intensif CPU. Ini untuk mengantri pekerjaan terikat I / O. Dan jika Anda ingin melakukan pekerjaan I / O, maka Anda harus menggunakan thread I / O (I / O Completion Port).

Secara khusus, Anda harus menggunakan async callback yang didukung oleh kelas library apa pun yang Anda gunakan. Metode ini selalu diberi label dengan sangat jelas; mereka mulai dengan kata-kata Begindan End. Seperti dalam Stream.BeginRead, Socket.BeginConnect, WebRequest.BeginGetResponse, dan sebagainya.

Metode ini menggunakan ThreadPool, tetapi mereka menggunakan IOCP, yang tidak mengganggu permintaan ASP.NET. Mereka adalah jenis benang ringan khusus yang dapat "dibangunkan" oleh sinyal interupsi dari sistem I / O. Dan dalam aplikasi ASP.NET, Anda biasanya memiliki satu utas I / O untuk setiap utas pekerja, sehingga setiap permintaan dapat memiliki satu operasi asinkron yang antri. Itu benar-benar ratusan operasi asinkron tanpa penurunan kinerja yang signifikan (dengan asumsi subsistem I / O dapat mengikutinya). Ini jauh lebih dari yang Anda butuhkan.

Perlu diingat bahwa delegasi asinkron tidak berfungsi dengan cara ini - mereka akan menggunakan thread pekerja, sama seperti ThreadPool.QueueUserWorkItem. Hanya metode async bawaan kelas pustaka .NET Framework yang mampu melakukan ini. Anda dapat melakukannya sendiri, tetapi ini rumit dan sedikit berbahaya dan mungkin di luar cakupan diskusi ini.

Jawaban terbaik untuk pertanyaan ini, menurut saya, adalah jangan gunakan ThreadPool atauThread contoh latar belakang di ASP.NET . Ini sama sekali tidak seperti memutar utas dalam aplikasi Windows Forms, di mana Anda melakukannya untuk menjaga agar UI tetap responsif dan tidak peduli seberapa efisiennya itu. Di ASP.NET, perhatian Anda adalah throughput , dan semua konteks yang beralih pada semua utas pekerja tersebut benar-benar akan mematikan throughput Anda apakah Anda menggunakan ThreadPoolatau tidak.

Tolong, jika Anda menemukan diri Anda menulis kode threading di ASP.NET - pertimbangkan apakah itu dapat ditulis ulang atau tidak untuk menggunakan metode asinkron yang sudah ada sebelumnya, dan jika tidak bisa, maka pertimbangkan apakah Anda benar-benar membutuhkan kode tersebut atau tidak untuk berjalan di utas latar belakang. Dalam sebagian besar kasus, Anda mungkin akan menambahkan kompleksitas tanpa keuntungan bersih.

Aaronaught
sumber
Terima kasih atas tanggapan rinci dan Anda benar, saya mencoba dan menggunakan metode async bila memungkinkan (digabungkan dengan pengontrol async di ASP.NET MVC). Dalam kasus contoh saya, dengan logger jarak jauh, inilah yang dapat saya lakukan. Ini adalah masalah desain yang menarik karena mendorong penanganan asinkron hingga ke level terendah dari kode Anda (yaitu, implementasi logger), alih-alih dapat memutuskannya dari, katakanlah, level pengontrol (dalam kasus terakhir , Anda memerlukan, misalnya, dua penerapan logger untuk dapat dipilih).
Michael Hart
@ Michael: Async callback umumnya cukup mudah untuk dibungkus jika Anda ingin menaikkannya lebih banyak level; Anda bisa membuat façade di sekitar metode async dan membungkusnya dengan satu metode yang menggunakan an Action<T>sebagai callback, misalnya. Jika yang Anda maksud adalah pilihan apakah akan menggunakan thread pekerja atau thread I / O terjadi di tingkat terendah, itu disengaja; hanya tingkat itu yang dapat memutuskan apakah perlu IOCP atau tidak.
Aaronaught
Meskipun, sebagai hal yang menarik, hanya .NET ThreadPoolyang membatasi Anda dengan cara ini, mungkin karena mereka tidak mempercayai pengembang untuk melakukannya dengan benar. Windows Thread Pool yang tidak dikelola memiliki API yang sangat mirip tetapi sebenarnya memungkinkan Anda untuk memilih jenis utas.
Aaronaught
2
Port Penyelesaian I / O (IOCP). deskripsi IOCP kurang tepat. di IOCP, Anda memiliki sejumlah thread pekerja yang bekerja secara bergiliran pada SEMUA tugas yang tertunda. jangan disamakan dengan kumpulan utas yang ukurannya dapat diperbaiki atau dinamis TETAPI memiliki satu utas per tugas - berskala sangat buruk. tidak seperti ASYNC, Anda tidak memiliki satu utas per tugas. utas IOCP mungkin bekerja sedikit pada tugas 1, lalu beralih ke tugas 3, tugas 2 lalu kembali ke tugas 1 lagi. status sesi tugas disimpan dan diteruskan di antara utas.
MickyD
1
Bagaimana dengan penyisipan database? Apakah ada perintah ASYNC SQL (seperti Execute)? Sisipan basis data adalah tentang operasi I / O paling lambat (karena penguncian) dan membuat utas utama menunggu baris disisipkan hanyalah pemborosan siklus CPU.
Ian Thompson
45

Menurut Thomas Marquadt dari tim ASP.NET di Microsoft, aman untuk menggunakan ASP.NET ThreadPool (QueueUserWorkItem).

Dari artikel :

T) Jika Aplikasi ASP.NET saya menggunakan utas CLR ThreadPool, apakah saya tidak akan membuat ASP.NET kelaparan, yang juga menggunakan CLR ThreadPool untuk menjalankan permintaan? ..

A) Untuk meringkas, jangan khawatir tentang ASP.NET yang kelaparan, dan jika menurut Anda ada masalah di sini, beri tahu saya dan kami akan menanganinya.

T) Haruskah saya membuat utas saya sendiri (utas baru)? Bukankah ini lebih baik untuk ASP.NET, karena menggunakan CLR ThreadPool.

A) Mohon jangan. Atau dengan kata lain, tidak !!! Jika Anda benar-benar pintar — jauh lebih pintar dari saya — maka Anda dapat membuat topik Anda sendiri; jika tidak, jangan pernah memikirkannya. Berikut beberapa alasan mengapa Anda tidak perlu sering-sering membuat utas baru:

  1. Ini sangat mahal, dibandingkan dengan QueueUserWorkItem ... Ngomong-ngomong, jika Anda dapat menulis ThreadPool yang lebih baik daripada CLR, saya mendorong Anda untuk melamar pekerjaan di Microsoft, karena kami pasti mencari orang-orang seperti Anda !.
Tim P.
sumber
4

Situs web tidak boleh mengelilingi utas pemijahan.

Anda biasanya memindahkan fungsi ini ke Layanan Windows yang kemudian berkomunikasi dengannya (saya menggunakan MSMQ untuk berbicara dengan mereka).

- Edit

Saya menjelaskan implementasinya di sini: Pemrosesan Latar Belakang Berbasis Antrean di Aplikasi Web ASP.NET MVC

- Edit

Untuk memperluas mengapa ini lebih baik dari sekedar utas:

Menggunakan MSMQ, Anda dapat berkomunikasi ke server lain. Anda dapat menulis ke antrian di seluruh mesin, jadi jika Anda menentukan, karena alasan tertentu, bahwa tugas latar belakang Anda menggunakan terlalu banyak sumber daya server utama, Anda dapat menggesernya dengan mudah.

Ini juga memungkinkan Anda untuk memproses tugas apa pun yang Anda coba lakukan (mengirim email / apa pun).

Sutra Siang
sumber
4
Saya tidak setuju bahwa pernyataan selimut ini selalu benar - terutama untuk tugas-tugas yang tidak kritis. Membuat Layanan Windows, hanya untuk tujuan pencatatan asinkron jelas terlihat berlebihan. Selain itu, opsi itu tidak selalu tersedia (dapat menerapkan MSMQ dan / atau Layanan Windows).
Michael Hart
Tentu, tetapi ini adalah cara 'standar' untuk mengimplementasikan tugas asinkron dari situs web (tema antrian terhadap beberapa proses lain).
Noon Silk
2
Tidak semua tugas asinkron dibuat sama, itulah sebabnya misalnya halaman asinkron ada di ASP.NET. Jika saya ingin mengambil hasil dari layanan web jarak jauh untuk ditampilkan, saya tidak akan melakukannya melalui MSMQ. Dalam hal ini, saya menulis ke log menggunakan posting jarak jauh. Tidak sesuai dengan masalah untuk menulis Layanan Windows, atau menghubungkan MSMQ untuk itu (dan saya juga tidak bisa karena aplikasi khusus ini ada di Azure).
Michael Hart
1
Pertimbangkan: Anda menulis ke host jarak jauh? Bagaimana jika host itu sedang down atau tidak dapat dihubungi? Apakah Anda ingin mencoba kembali tulisan Anda? Mungkin Anda mau, mungkin tidak. Dengan penerapan Anda, sulit untuk mencoba lagi. Dengan adanya layanan tersebut, menjadi hal yang cukup sepele. Saya menghargai bahwa Anda mungkin tidak dapat melakukannya, dan saya akan membiarkan orang lain menjawab masalah khusus dengan membuat utas dari situs web [yaitu jika utas Anda tidak berlatar belakang, dll], tetapi saya menguraikan yang 'tepat' cara untuk melakukannya. Saya tidak terbiasa dengan azure, meskipun saya telah menggunakan ec2 (Anda dapat menginstal OS itu, jadi semuanya baik-baik saja).
Noon Silk
@silky, terima kasih atas komentarnya. Saya telah mengatakan "tidak kritis" untuk menghindari solusi yang lebih berat (namun tahan lama) ini. Saya telah mengklarifikasi pertanyaan tersebut sehingga jelas saya tidak meminta praktik terbaik seputar item pekerjaan yang antri. Azure memang mendukung jenis skenario ini (ia memiliki penyimpanan antriannya sendiri) - tetapi operasi antrian terlalu mahal untuk pencatatan log sinkron, jadi saya tetap memerlukan solusi asinkron. Dalam kasus saya, saya mengetahui jebakan kegagalan, tetapi saya tidak akan menambahkan lebih banyak infrastruktur untuk berjaga-jaga jika penyedia logging khusus ini gagal - saya juga memiliki penyedia logging lain.
Michael Hart
4

Saya pasti berpikir bahwa praktik umum untuk pekerjaan asinkron cepat dan prioritas rendah di ASP.NET akan menggunakan kumpulan utas .NET, terutama untuk skenario lalu lintas tinggi karena Anda ingin sumber daya Anda dibatasi.

Selain itu, implementasi threading disembunyikan - jika Anda mulai menelurkan utas Anda sendiri, Anda harus mengelolanya dengan benar juga. Bukan mengatakan Anda tidak bisa melakukannya, tetapi mengapa menciptakan kembali roda itu?

Jika kinerja menjadi masalah, dan Anda dapat menetapkan bahwa kumpulan utas adalah faktor pembatas (dan bukan koneksi database, koneksi jaringan keluar, memori, waktu tunggu halaman, dll.) Maka Anda mengubah konfigurasi kumpulan utas untuk memungkinkan lebih banyak utas pekerja, permintaan antrian yang lebih tinggi , dll.

Jika Anda tidak memiliki masalah kinerja maka memilih untuk menelurkan utas baru untuk mengurangi perselisihan dengan antrian permintaan ASP.NET adalah pengoptimalan prematur klasik.

Idealnya Anda tidak perlu menggunakan utas terpisah untuk melakukan operasi pencatatan - cukup aktifkan utas asli untuk menyelesaikan operasi secepat mungkin, di mana MSMQ dan utas / proses konsumen yang terpisah masuk ke gambar. Saya setuju bahwa ini lebih berat dan lebih banyak pekerjaan untuk diterapkan, tetapi Anda benar-benar membutuhkan daya tahan di sini - volatilitas antrean bersama dalam memori akan cepat usang.

Sam
sumber
2

Anda harus menggunakan QueueUserWorkItem, dan menghindari membuat utas baru seperti Anda akan menghindari wabah. Untuk visual yang menjelaskan mengapa Anda tidak akan membuat ASP.NET kelaparan, karena menggunakan ThreadPool yang sama, bayangkan pemain sulap yang sangat terampil menggunakan dua tangan untuk menyimpan setengah lusin pin bowling, pedang, atau apa pun dalam penerbangan. Untuk gambaran mengapa membuat utas Anda sendiri itu buruk, bayangkan apa yang terjadi di Seattle pada jam-jam sibuk ketika jalur masuk yang banyak digunakan ke jalan raya memungkinkan kendaraan langsung memasuki lalu lintas alih-alih menggunakan lampu dan membatasi jumlah pintu masuk menjadi satu setiap beberapa detik . Terakhir, untuk penjelasan detailnya, silakan lihat tautan ini:

http://blogs.msdn.com/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

Terima kasih, Thomas

Thomas
sumber
Tautan itu sangat berguna, terima kasih Thomas. Saya juga tertarik untuk mendengar pendapat Anda tentang tanggapan @ Aaronaught.
Michael Hart
Saya setuju dengan Aaronaught, dan mengatakan hal yang sama di postingan blog saya. Saya mengatakannya seperti ini, "Dalam upaya untuk menyederhanakan keputusan ini, Anda sebaiknya hanya beralih [ke utas lain] jika Anda akan memblokir utas permintaan ASP.NET saat Anda tidak melakukan apa-apa. Ini adalah penyederhanaan yang berlebihan, tetapi saya mencoba untuk membuat keputusan sederhana. " Dengan kata lain, jangan lakukan itu untuk pekerjaan komputasi non-pemblokiran, tetapi lakukan jika Anda membuat permintaan layanan web asinkron ke server jarak jauh. Dengarkan Aaronaught! :)
Thomas
1

Artikel itu tidak benar. ASP.NET memiliki kumpulan utasnya sendiri, utas pekerja terkelola, untuk melayani permintaan ASP.NET. Kumpulan ini biasanya terdiri dari beberapa ratus utas dan terpisah dari kumpulan ThreadPool, yang merupakan kelipatan prosesor yang lebih kecil.

Menggunakan ThreadPool di ASP.NET tidak akan mengganggu thread pekerja ASP.NET. Menggunakan ThreadPool baik-baik saja.

Ini juga dapat diterima untuk menyiapkan satu utas yang hanya untuk mencatat pesan dan menggunakan pola produsen / konsumen untuk meneruskan pesan log ke utas itu. Dalam hal ini, karena utas berumur panjang, Anda harus membuat satu utas baru untuk menjalankan logging.

Menggunakan utas baru untuk setiap pesan pasti berlebihan.

Alternatif lain, jika Anda hanya berbicara tentang logging, adalah menggunakan library seperti log4net. Ini menangani logging di utas terpisah dan menangani semua masalah konteks yang bisa muncul dalam skenario itu.

Samuel Neff
sumber
1
@ Sam, saya sebenarnya menggunakan log4net dan tidak melihat log yang ditulis di utas terpisah - apakah ada semacam opsi yang perlu saya aktifkan?
Michael Hart
1

Saya akan mengatakan artikel itu salah. Jika Anda menjalankan toko .NET yang besar, Anda dapat dengan aman menggunakan kumpulan di beberapa aplikasi dan beberapa situs web (menggunakan kumpulan aplikasi terpisah), hanya berdasarkan satu pernyataan di dokumentasi ThreadPool :

Ada satu kumpulan utas per proses. Kumpulan thread memiliki ukuran default 250 thread pekerja per prosesor yang tersedia, dan 1000 thread penyelesaian I / O. Jumlah utas di kumpulan utas dapat diubah dengan menggunakan metode SetMaxThreads. Setiap utas menggunakan ukuran tumpukan default dan berjalan pada prioritas default.

Christopher Nobles
sumber
Satu aplikasi yang berjalan dalam satu proses sepenuhnya mampu menurunkan dirinya sendiri! (Atau setidaknya menurunkan kinerjanya sendiri sehingga membuat kumpulan utas menjadi proposisi yang kalah.)
Jeff Sternal
Jadi saya menebak permintaan ASP.NET menggunakan utas penyelesaian I / O (sebagai lawan utas pekerja) - apakah itu benar?
Michael Hart
Dari artikel Fritz Onion saya menautkan jawaban saya: "Paradigma ini berubah [dari IIS 5.0 ke IIS 6.0] cara permintaan ditangani di ASP.NET. Alih-alih mengirimkan permintaan dari inetinfo.exe ke proses pengerjaan ASP.NET, http. sys secara langsung mengantrekan setiap permintaan dalam proses yang sesuai. Jadi, semua permintaan sekarang dilayani oleh thread pekerja yang diambil dari kumpulan thread CLR dan tidak pernah di thread I / O ". (penekanan saya)
Jeff Sternal
Hmmm, saya masih belum sepenuhnya yakin ... Artikel itu berasal dari Juni 2003. Jika Anda membaca yang ini dari Mei 2004 (memang masih cukup lama), dikatakan "Halaman pengujian Sleep.aspx dapat digunakan untuk menyimpan ASP .NET I / O thread busy ", di mana Sleep.aspx hanya menyebabkan thread yang sedang dieksekusi tertidur: msdn.microsoft.com/en-us/library/ms979194.aspx - Ketika saya punya kesempatan, saya akan melihat jika saya dapat membuat kode contoh itu dan menguji di IIS 7 dan .NET 3.5
Michael Hart
Ya, teks paragraf itu membingungkan. Lebih jauh di bagian itu, tautan ini menautkan ke topik dukungan ( support.microsoft.com/default.aspx?scid=kb;EN-US;816829 ) yang menjelaskan hal-hal: menjalankan permintaan pada utas penyelesaian I / O adalah .NET Framework 1.0 masalah yang telah diperbaiki di ASP.NET 1.1 Juni 2003 Paket Rollup Hotfix (setelah itu "SEMUA permintaan sekarang berjalan di thread pekerja"). Lebih penting lagi, contoh tersebut menunjukkan dengan cukup jelas bahwa kumpulan benang ASP.NET adalah kumpulan benang yang sama yang diekspos oleh System.Threading.ThreadPool.
Jeff Sternal
1

Saya ditanyai pertanyaan serupa di tempat kerja minggu lalu dan saya akan memberikan jawaban yang sama. Mengapa Anda menggunakan aplikasi web multi threading per permintaan? Server web adalah sistem fantastis yang sangat dioptimalkan untuk menyediakan banyak permintaan secara tepat waktu (mis. Multi threading). Pikirkan apa yang terjadi jika Anda meminta hampir semua halaman di web.

  1. Permintaan dibuat untuk beberapa halaman
  2. Html disajikan kembali
  3. Html memberi tahu klien untuk membuat permintaan ulang lebih lanjut (js, css, gambar, dll ..)
  4. Informasi lebih lanjut disajikan kembali

Anda memberi contoh penebangan jarak jauh, tapi itu harus menjadi perhatian logger Anda. Proses asynchronous harus ada untuk menerima pesan secara tepat waktu. Sam bahkan menunjukkan bahwa logger Anda (log4net) seharusnya sudah mendukung ini.

Sam juga benar karena menggunakan Thread Pool di CLR tidak akan menyebabkan masalah dengan kumpulan thread di IIS. Hal yang harus diperhatikan di sini adalah bahwa Anda tidak memijah utas dari suatu proses, Anda menelurkan utas baru dari utas threadpool IIS. Ada perbedaan dan perbedaan itu penting.

Untaian vs Proses

Baik utas maupun proses adalah metode untuk memparalelkan aplikasi. Namun, proses adalah unit eksekusi independen yang berisi informasi statusnya sendiri, menggunakan ruang alamatnya sendiri, dan hanya berinteraksi satu sama lain melalui mekanisme komunikasi antarproses (umumnya dikelola oleh sistem operasi). Aplikasi biasanya dibagi menjadi beberapa proses selama fase desain, dan proses master secara eksplisit memunculkan sub-proses saat masuk akal untuk memisahkan fungsionalitas aplikasi yang signifikan secara logis. Proses, dengan kata lain, adalah konstruksi arsitektural.

Sebaliknya, utas adalah konstruksi pengkodean yang tidak memengaruhi arsitektur aplikasi. Satu proses mungkin berisi banyak utas; semua utas dalam proses berbagi keadaan yang sama dan ruang memori yang sama, dan dapat berkomunikasi satu sama lain secara langsung, karena mereka berbagi variabel yang sama.

Sumber

Ty.
sumber
3
@Ty, terima kasih atas masukannya, tetapi saya sangat menyadari cara kerja server web dan itu tidak benar-benar relevan dengan pertanyaan - sekali lagi, seperti yang saya katakan dalam pertanyaan, saya tidak meminta panduan tentang ini sebagai arsitektur isu. Saya meminta informasi teknis khusus. Adapun itu menjadi "perhatian logger" yang seharusnya sudah memiliki proses asynchronous - bagaimana menurut Anda bahwa proses asynchronous harus ditulis oleh implementasi logger?
Michael Hart
0

Saya tidak setuju dengan artikel yang dirujuk (C # feeds.com). Sangat mudah untuk membuat utas baru tetapi berbahaya. Jumlah optimal utas aktif untuk dijalankan pada satu inti sebenarnya sangat rendah - kurang dari 10. Terlalu mudah untuk menyebabkan mesin membuang waktu untuk mengganti utas jika utas dibuat untuk tugas-tugas kecil. Utas adalah sumber daya yang MEMBUTUHKAN manajemen. Abstraksi WorkItem ada untuk menangani ini.

Ada pertukaran di sini antara mengurangi jumlah utas yang tersedia untuk permintaan dan membuat terlalu banyak utas untuk memungkinkan salah satu dari mereka diproses secara efisien. Ini adalah situasi yang sangat dinamis tetapi saya pikir salah satu yang harus dikelola secara aktif (dalam hal ini oleh kumpulan utas) daripada menyerahkannya kepada pemroses untuk tetap menjadi yang terdepan dalam pembuatan utas.

Akhirnya artikel tersebut membuat beberapa pernyataan yang cukup luas tentang bahaya menggunakan ThreadPool tetapi benar-benar membutuhkan sesuatu yang konkret untuk mendukungnya.

Timbo
sumber
0

Apakah IIS menggunakan ThreadPool yang sama untuk menangani permintaan masuk tampaknya sulit untuk mendapatkan jawaban pasti, dan juga tampaknya telah berubah seiring versi. Jadi sepertinya ide yang bagus untuk tidak menggunakan thread ThreadPool secara berlebihan, sehingga IIS memiliki banyak dari mereka yang tersedia. Di sisi lain, memunculkan utas Anda sendiri untuk setiap tugas kecil sepertinya ide yang buruk. Agaknya, Anda memiliki semacam penguncian di logging Anda, jadi hanya satu utas yang dapat maju pada satu waktu, dan sisanya hanya akan bergiliran menjadwalkan dan tidak terjadwal (belum lagi overhead pemijahan utas baru). Pada dasarnya, Anda mengalami masalah yang sebenarnya dirancang untuk dihindari ThreadPool.

Tampaknya kompromi yang masuk akal adalah jika aplikasi Anda mengalokasikan satu utas logging yang dapat Anda kirimi pesan. Anda ingin berhati-hati bahwa pengiriman pesan secepat mungkin sehingga Anda tidak memperlambat aplikasi Anda.

bmm6o
sumber
0

Anda dapat menggunakan Parallel.For atau Parallel.ForEach dan menentukan batas kemungkinan utas yang ingin Anda alokasikan agar berjalan lancar dan mencegah kelaparan kumpulan.

Namun, dijalankan di latar belakang Anda perlu menggunakan gaya TPL murni di bawah ini dalam aplikasi web ASP.Net.

var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;

ParallelOptions po = new ParallelOptions();
            po.CancellationToken = ts.Token;
            po.MaxDegreeOfParallelism = 6; //limit here

 Task.Factory.StartNew(()=>
                {                        
                  Parallel.ForEach(collectionList, po, (collectionItem) =>
                  {
                     //Code Here PostLog(logEvent);
                  }
                });
khayam
sumber