Tutorial Pasukan Lucee MY

cfthread: konkurensi dan pemprosesan tak segerak dalam CFML

Panduan cfthread Lucee: jalankan utas tak segerak, kongsi nilai melalui skop thread, tunggu dengan join dan had masa, dan kendali kegagalan utas dengan betul.

cfthread: konkurensi dan pemprosesan tak segerak dalam CFML
0
Kandungan

cfthread: konkurensi dan pemprosesan tak segerak dalam CFML

cfthread ialah tag teras Lucee untuk menjalankan blok kod dalam utas berasingan, selari dengan permintaan halaman utama. Setiap utas mendapat skop thread tersendiri, dan anda menunggu hasilnya dengan action="join". Artikel ini menunjukkan cara mencipta utas, berkongsi nilai, menunggu dengan had masa, dan menangani kegagalan utas dengan betul. Dua konsep utama yang perlu dikuasai ialah skop thread dan cara menunggu utas selesai. Corak yang ditunjukkan di sini disahkan berjalan pada Lucee 7.1.

Apa itu cfthread dan Bila Menggunakannya

cfthread membenarkan kod anda melakukan beberapa kerja serentak dalam satu permintaan. Kes penggunaan lazim ialah memanggil dua API luaran pada masa yang sama, menghantar e-mel tanpa menyekat halaman, atau menjalankan pengiraan berat di latar belakang. Secara lalai type ialah daemon, yang bermakna utas hidup dalam permintaan semasa. Nilai task pula membolehkan utas berulang dengan atribut retryInterval.

Bersama cfthread, Lucee menyediakan fungsi berkaitan untuk memeriksa dan mengawal utas. IsInThread() memberitahu sama ada kod sedang berjalan di dalam utas, ThreadData() memulangkan metadata utas, ThreadJoin() menunggu utas lain, manakala ThreadTerminate() dan ThreadInterrupt() menghentikan utas. Atribut priority menerima HIGH, NORMAL (lalai) atau LOW untuk mempengaruhi penjadualan utas.

Apabila tugas melibatkan banyak permintaan HTTP, ia selalunya berpasangan dengan cfhttp yang dibincangkan dalam artikel panggilan API luaran. Perlu diingat bahawa utas bukan pengganti caching: kerja yang sama dijalankan berulang kali pada setiap permintaan tetap membebankan pelayan, dan teknik yang diterangkan dalam panduan caching dan prestasi lebih sesuai untuk data yang jarang berubah.

Mencipta Utas dan Skop thread

Untuk memulakan utas, gunakan action="run" (nilai lalai) dengan atribut name yang unik. Nilai yang anda hantar ke utas diletakkan sebagai atribut, dan di dalam utas anda membacanya melalui skop attributes. Hasil kerja disimpan ke skop thread, yang kemudiannya boleh dibaca dari luar selepas utas selesai:

<cfthread action="run" name="t1" nama="Lucee">
    <cfset thread.hasil = ucase(attributes.nama)>
</cfthread>

<cfthread action="join" name="t1" timeout="5000" throwOnError="true" />

<cfoutput>#t1.hasil#</cfoutput>

Penting untuk faham bahawa skop thread adalah berasingan daripada skop lain. Nilai yang anda set di dalam utas tidak muncul dalam skop variables halaman utama, dan sebaliknya. Satu-satunya jambatan ialah skop thread yang dinamakan mengikut atribut name, dan nilai yang dihantar sebagai atribut. Lucee menghantar atribut ini secara rujukan, berbeza dengan Adobe ColdFusion yang menghantar salinan, jadi objek boleh berubah di dalam utas. Perincian skop ini dihuraikan lebih lanjut dalam panduan memahami skop CFML.

action="join" menangguhkan utas semasa sehingga utas yang dinamakan selesai. Atribut timeout mengambil masa dalam milisaat: nilai 0 bermakna tunggu tanpa had, manakala nombor positif membolehkan utas semasa menyambung semula selepas tempoh itu walaupun utas sasaran belum siap. Anda boleh menyenaraikan beberapa utas dalam satu join dengan senarai dipisahkan koma. Contoh berikut menjalankan dua panggilan API selari dan menunggu kedua-duanya:

<cfthread action="run" name="cuaca">
    <cfhttp url="https://api.contoh.com/cuaca" method="get" result="r">
    </cfhttp>
    <cfset thread.hasil = deserializeJSON(r.fileContent)>
</cfthread>

<cfthread action="run" name="berita">
    <cfhttp url="https://api.contoh.com/berita" method="get" result="r">
    </cfhttp>
    <cfset thread.hasil = deserializeJSON(r.fileContent)>
</cfthread>

<cfthread action="join" name="cuaca,berita" timeout="10000" />

<cfdump var="#cuaca.hasil#">
<cfdump var="#berita.hasil#">

Dengan join, kerja yang dahulunya mengambil masa penuh dua panggilan berturutan kini hanya mengambil masa panggilan paling perlahan. Apabila join menyenaraikan beberapa utas, Lucee menunggu semuanya sebelum utas semasa meneruskan.

Skop Berasingan dan separateScopes

Atribut separateScopes, tersedia sejak Lucee 6.1.0.151 dan hanya untuk action="run", mengawal sama ada utas mendapat salinan skop pemanggil atau berkongsi secara terus. Nilai lalai true memberi utas satu salinan dalam skop pemanggil, jadi perubahan dalam utas tidak menjejaskan konteks induk dan sebaliknya. Ini pengasingan yang anda mahukan pada kebiasaannya.

Perlu diingat bahawa salinan itu ialah salinan dalam, dibuat pada masa utas dicipta. Nilai yang anda ubah pada skop pemanggil selepas utas dimulakan tidak akan sampai ke utas itu kecuali anda menghantarnya sebagai atribut atau menggunakan separateScopes=false.

Menetapkan separateScopes="false" membuat utas mengakses skop pemanggil secara langsung, jadi perubahan kelihatan serta-merta kepada kedua-dua pihak. Ini berisiko: race condition boleh berlaku apabila dua utas menulis nilai yang sama serentak. Satu peraturan praktikal yang penting: jangan biarkan kerja utas menyentuh skop form atau url, kerana skop itu milik permintaan halaman dan tidak wujud dengan bermakna di dalam utas. Hantar apa yang diperlukan sebagai atribut dan baca melalui skop attributes.

Mengendalikan Kegagalan Utas

Apabila utas gagal, exception tidak keluar ke halaman utama. Ralat itu terperangkap di dalam skop thread utas itu sendiri, jadi anda mesti menangkapnya di dalam utas, bukan di luar. Corak yang selamat ialah membungkus kerja dalam cftry, menyimpan status dan mesej ralat ke skop thread, dan menyemaknya selepas join:

<cfthread action="run" name="kerja">
    <cftry>
        <cfhttp url="https://api.contoh.com/data" method="get" result="r" throwOnError="true">
        </cfhttp>
        <cfset thread.hasil = deserializeJSON(r.fileContent)>
        <cfset thread.ok = true>
        <cfcatch>
            <cfset thread.ok = false>
            <cfset thread.ralat = cfcatch.message>
        </cfcatch>
    </cftry>
</cfthread>

<cfthread action="join" name="kerja" timeout="5000" />

<cfif kerja.ok>
    <cfdump var="#kerja.hasil#">
<cfelse>
    <cfoutput>Gagal: #kerja.ralat#</cfoutput>
</cfif>

Jika anda mahu ralat dibuang ke utas yang menunggu, set throwOnError="true" pada action="join". Dengan nilai lalai false, ralat kekal terasing dalam skop thread masing-masing dan anda mesti memeriksanya secara eksplisit. Satu perkara yang mudah terlepas: output debug setiap utas tidak muncul dalam laporan debug halaman utama, jadi gunakan panduan log dan pemantauan untuk merakam apa yang berlaku di dalam utas.

type=task dan retryInterval

Selain daemon, type="task" menandakan utas sebagai tugas yang boleh diulang. Atribut retryInterval, yang hanya sah untuk type="task", menerima struct dengan kekunci interval dalam milisaat dan tries untuk bilangan percubaan, atau array struct bagi jadual cubaan bertingkat. Ini berguna untuk kerja latar belakang yang perlu dicuba semula sehingga berjaya, contohnya menghantar panggilan balik ke pelayan yang sementara tidak dapat dihubungi:

<cfscript>
    thread name="proses" type="task"
        retryInterval = { interval = 2000, tries = 3 } {
        thread.hasil = cubaKerja();
    }
</cfscript>

Ejaan lama retryintervall masih diterima sebagai alias, tetapi gunakan retryInterval dalam kod baharu.

terminate lawan interrupt

Dua cara menghentikan utas wujud dengan sifat yang berbeza. terminate memaksa utas berhenti serta-merta dan dianggap non-cooperative, bermakna ia boleh meninggalkan sumber seperti sambungan pangkalan data dalam keadaan tidak konsisten. interrupt, tersedia sejak Lucee 7.0.0.120, menetapkan bendera interrupt dan membolehkan utas membersihkan sumber sebelum berhenti, jadi ia lebih selamat untuk kebanyakan keadaan. Fungsi ThreadTerminate() dan ThreadInterrupt() memberi laluan skrip kepada dua tindakan yang sama. Untuk menangguhkan utas semasa, action="sleep" bersama atribut duration dalam milisaat membolehkan anda mengehadkan kadar tanpa mencipta kebergantungan utas penuh.

Soalan Lazim (FAQ)

Kenapa nilai saya tidak kelihatan dalam utas?

Skop thread berasingan daripada skop lain. Semak bahawa anda menghantar nilai sebagai atribut dan membacanya melalui skop attributes, dan selepas join baca hasil melalui skop thread yang dinamakan mengikut atribut name.

Bolehkah saya akses form atau url dalam utas?

Tidak selamat. Skop form dan url milik permintaan halaman. Hantar nilai yang diperlukan ke utas sebagai atribut dan baca melalui skop attributes di dalam utas.

Bagaimana cara menunggu semua utas siap dengan had masa?

Guna action="join" dengan atribut timeout dalam milisaat. Nilai 0 bermakna tunggu tanpa had, manakala nombor positif membolehkan utas semasa menyambung selepas tempoh itu walaupun utas sasaran belum siap.

Apa yang berlaku jika utas gagal?

Ralat kekal dalam skop thread utas itu. Tangkap dengan cftry di dalam utas dan simpan mesej ke skop thread, atau set throwOnError="true" pada join untuk membiarkan ralat merebak ke utas yang menunggu.

Bolehkah saya menghentikan utas dengan bersih?

Guna action="interrupt" (sejak Lucee 7.0.0.120) untuk hentian kooperatif yang membolehkan pembersihan, bukan action="terminate" yang boleh meninggalkan sumber tidak konsisten.

Sumber

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk