229 ការអាន

គ្មានឧបករណ៍ដែលអាចគ្រប់គ្រងការធ្វើតេស្តផ្ទុករបស់យើងសម្រាប់ហ្គេម - ដូច្នេះយើងបានបង្កើត Swarm

ដោយ Andrew Rakhubov19m2025/05/20
Read on Terminal Reader

យូរ​ពេក; អាន

យើងត្រូវការឧបករណ៍ធ្វើតេស្តផ្ទុកដែលមានជំនាញវិជ្ជាជីវៈដែលអាចគ្រប់គ្រងប្រព័ន្ធប្រតិបត្តិការ WebSocket+Protobuf ដែលអាចគ្រប់គ្រងប្រព័ន្ធប្រតិបត្តិការ inter-bot និងការធ្វើតេស្តធំទូលំទូលាយ។ ឧបករណ៍ដែលមាននៅពេលនេះបានកាត់បន្ថយ, ដូច្នេះពួកគេបានបង្កើត Swarm: ប្រព័ន្ធប្រតិបត្តិការ C# ដែលមានប្រព័ន្ធប្រតិបត្តិការ “ប៊ូត” ដែលអាចគ្រប់គ្រងប្រព័ន្ធប្រតិបត្តិការតាមរយៈប្រព័ន្ធប្រតិបត្តិការកំណត់គ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងដោយប្រើការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រងការគ្រប់គ្រង
featured image - គ្មានឧបករណ៍ដែលអាចគ្រប់គ្រងការធ្វើតេស្តផ្ទុករបស់យើងសម្រាប់ហ្គេម - ដូច្នេះយើងបានបង្កើត Swarm
Andrew Rakhubov HackerNoon profile picture
0-item
1-item

របៀបដែលយើងបានរចនា Swarm, ប្រព័ន្ធសាកល្បងផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុក

របៀបដែលយើងបានរចនា Swarm, ប្រព័ន្ធសាកល្បងផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុកផ្ទុក


ឥឡូវនេះវាគឺជាការងាយស្រួលណាស់ដើម្បីរចនាឡើងនូវផលិតកម្មកម្មវិធីដែលមិនមានមួយចំនួនការធ្វើតេស្តកម្រិតនៃការធ្វើតេស្ត។ ការធ្វើតេស្តឧបករណ៍គឺជាវិធីសាស្រ្តធម្មតានៅក្នុងការកាត់បន្ថយកំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់កំណត់ក


ខ្ញុំជា Andrey Rakhubov ដែលជាអ្នកវិស្វករកម្មវិធីសំខាន់នៅ MY.GAMES! នៅក្នុងប្រកាសនេះខ្ញុំនឹងផ្លាស់ប្តូរទិន្នន័យអំពីការផ្លាស់ប្តូរដែលប្រើនៅក្នុងសាកលវិទ្យាល័យរបស់យើងនិងវិធីសាស្រ្តរបស់យើងក្នុងការធ្វើតេស្តការផ្ទុកនៃការធ្វើតេស្ត meta-game នៅ War Robots: Frontiers ។

សៀវភៅសៀវភៅសៀវភៅសៀវភៅសៀវភៅសៀវភៅសៀវភៅសៀវភៅ

ដោយគ្មានការចូលទៅក្នុងលក្ខណៈពិសេសណាមួយដែលមិនចាំបាច់, ការបង្វិលរបស់យើងរួមបញ្ចូលគ្នាជាប្រភេទនៃសេវាកម្មអាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាសអាភាស។

backend architecture overview

ទោះជាយ៉ាងណាក៏ដោយមានបញ្ហានៃការផ្សេងទៀតដែលអាចមានវិធីសាស្រ្តនេះបានបង្ហាញថាវាគឺជាការល្អណាស់ក្នុងការដោះស្រាយមួយនៃបញ្ហានេះដែលមានភាពងាយស្រួលបំផុតនៅក្នុងការអភិវឌ្ឍន៍ហ្គេម: ល្បឿន iteration ។ អ្នកអាចយល់ថាក្នុងរយៈពេលដំបូងនៃការអភិវឌ្ឍន៍ Rust-lang មានការហ្គេមថាឯកសារនឹងផ្លាស់ប្តូរដូចដែលអ្នកបានអាន។នេះដូច្នេះយើងមានន័យដូចគ្នាអំពីឯកសារ GDD (Game Design Document) ។


អ្នកជំនាញបានជួយក្នុងវិធីដែលពួកគេគឺជាការងាយស្រួលក្នុងការអនុវត្តនិងការផ្លាស់ប្តូរនៅក្នុងជំហានដំបូងនៃការរចនាសម្ព័ន្ធលក្ខណៈពិសេសនិងពួកគេគឺជាការងាយស្រួលក្នុងការ refactor ជាសេវាកម្មដោយផ្ទាល់ប្រសិនបើតម្រូវការកើតឡើងបន្ទាប់មក។


ការធ្វើតេស្តផ្ទុកនិងការរួមបញ្ចូលនេះមានភាពងាយស្រួលប្រសិនបើអ្នកមិនមានការបាត់បង់សេវាកម្មយ៉ាងច្បាស់លាស់ជាមួយនឹង API ដែលមានគុណភាពខ្ពស់និងមានតម្រូវការខ្ពស់។ ដូច្នេះអ្នកមិនមានការបាត់បង់សេវាកម្មដែលមានតម្រូវការខុសគ្នានិងអាចត្រួតពិនិត្យបានយ៉ាងហោចណាស់។

ការធ្វើតេស្ត

ដូចដែលអ្នកអាចជឿទុកចិត្ត, ការធ្វើតេស្តឧបករណ៍សម្រាប់កម្មវិធីនិងសេវាកម្ម (និងការធ្វើតេស្តផ្ទុក / ការបណ្តុះបណ្តាលសម្រាប់សេវាកម្ម) មិនមានប្រភេទផ្សេងគ្នានៃអ្វីដែលអ្នកនឹងរកឃើញនៅក្នុងប្រភេទផ្សេងទៀតនៃកម្មវិធី។ ការផ្សេងគ្នានៅក្នុង:

  • ការធ្វើតេស្តផ្ទុកនិងការរួមបញ្ចូល
  • ការធ្វើតេស្ត end-to-end និង load backend


យើងនឹងមិនមើលឃើញការធ្វើតេស្តនៃការធ្វើតេស្តនៅក្នុងពិសេសនៅទីនេះដោយសារតែវាមិនមានលក្ខណៈពិសេសសម្រាប់ GameDev ទេប៉ុន្តែទាក់ទងទៅនឹងម៉ូដែលអ្នកធ្វើតេស្តរបស់ខ្លួន។ គោលបំណងដែលធម្មតានៅក្នុងការធ្វើតេស្តនេះគឺមានក្លឹបមួយគត់មួយដែលអាចត្រូវបានបណ្តុះបណ្តាលនៅក្នុងការចែកចាយក្នុងការធ្វើតេស្តតែមួយហើយដែលអាចបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះបណ្តុះប


ដូច្នេះអ្វីដែលបានចាប់ផ្តើមបានចាប់ផ្តើមមានភាពងាយស្រួលបំផុតនៅពេលដែលយើងបានមកដល់ការផ្ទុកឬការធ្វើតេស្ត end-to-end - និងទីនេះគឺជាការចាប់ផ្តើមនៃប្រវត្តិសាស្រ្តរបស់យើង។


ដូច្នេះនៅក្នុងការរបស់យើងកម្មវិធីអតិថិជនគឺហ្គេមដោយខ្លួនឯង។ ហ្គេមប្រើម៉ាស៊ីន Unreal, ដូច្នេះកូដត្រូវបានសរសេរនៅក្នុង C++, និងនៅលើបណ្តាញយើងប្រើ C# ។ អ្នកលេងផ្លាស់ប្តូរជាមួយអេឡិចត្រូនិអេឡិចត្រូនិនៅក្នុងហ្គេម, ការផលិតតម្រូវការទៅ backend (ឬតម្រូវការត្រូវបានធ្វើដោយប្រាកដ) ។


នៅពេលនេះអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជនអតិថិជន


ចំណុចបន្ទាប់នេះគឺថាយើងប្រើប្រព័ន្ធប្រតិបត្តិការទំនាក់ទំនងផ្ទាល់ខ្លួនរវាងអតិថិជននិង backend ។ ការផ្លាស់ប្តូរនេះពិតជាគួរឱ្យមានអត្ថបទផ្ទាល់ខ្លួនទេប៉ុន្តែខ្ញុំនឹងបង្ហាញនូវគំនិតសំខាន់ៗនេះ:

  • ការទំនាក់ទំនងធ្វើឡើងតាមរយៈការតភ្ជាប់ WebSocket
  • វាគឺជាគំនិតជាលើកដំបូង; យើងប្រើ Protobuf ដើម្បីកំណត់រចនាសម្ព័ន្ធព័ត៌មាននិងសេវាកម្ម
  • ការប្រកាស WebSocket គឺជាការប្រកាស Protobuf ដែលត្រូវបានវេចខ្ចប់ទៅក្នុងកញ្ចក់ដែលមានទិន្នន័យប្លាស្ទិចដែលធ្វើឱ្យប្រសើរឡើងនូវទិន្នន័យ gRPC ដែលត្រូវការដូចជា URL និង headers ។

ដូច្នេះឧបករណ៍ណាមួយដែលមិនអនុញ្ញាតឱ្យកំណត់ប្រព័ន្ធប្រតិបត្តិការផ្ទាល់ខ្លួនគឺមិនសមរម្យសម្រាប់ការងារនេះ។

ឧបករណ៍ផ្ទុកដើម្បីធ្វើតេស្តពួកគេទាំងអស់

នៅពេលនេះយើងចង់មានឧបករណ៍តែមួយដែលអាចសរសេរការធ្វើតេស្តផ្ទុក REST / gRPC និងការធ្វើតេស្ត end-to-end ជាមួយនឹងប្រព័ន្ធផ្សព្វផ្សាយផ្ទាល់ខ្លួនរបស់យើង។ បន្ទាប់ពីគិតអំពីតម្រូវការទាំងអស់ដែលត្រូវបានពិភាក្សានៅក្នុងការធ្វើតេស្តនិងការពិភាក្សាដំបូងមួយចំនួនយើងត្រូវបានបាត់បង់ជាមួយគម្រោងទាំងនេះ:


K6 ។សត្វហ្វេសប៊ុក

ពួកគេទាំងអស់មានគោលបំណងនិងគោលបំណងរបស់ពួកគេ, ប៉ុន្តែមានច្រើននៃអ្វីដែលពួកគេមិនអាចដោះស្រាយដោយគ្មានការផ្លាស់ប្តូរធំទូលំទូលាយ (ម្តងទៀតផ្ទាល់) ។


  • ជាលើកដំបូង, មានតម្រូវការដែលទាក់ទងនឹងការទំនាក់ទំនងរវាង bot សម្រាប់គោលបំណងនៃការសន្សំ, ដូចដែលបាននិយាយមុន។
  • ទីពីរ, កុំព្យូទ័រមានប្រសិទ្ធភាពយ៉ាងខ្លាំងនិងស្ថានភាពរបស់ពួកគេអាចផ្លាស់ប្តូរដោយគ្មានការដោះស្រាយដោយពិសេសពីប្រសិនបើមានប្រសិនបើមានការធ្វើតេស្ត; នេះធ្វើឱ្យមានការត្រួតពិនិត្យបន្ថែមទៀតនិងការតម្រូវការដើម្បីដោះស្រាយតាមរយៈការដោះស្រាយជាច្រើននៅក្នុងកូដរបស់អ្នក។
  • ទោះជាយ៉ាងណាក៏ដោយឧបករណ៍ទាំងនេះត្រូវបានផ្តោតលើការធ្វើតេស្តប្រសិទ្ធភាពយ៉ាងតឹងរឹងដោយផ្តល់នូវលក្ខណៈពិសេសជាច្រើនសម្រាប់ការកើនឡើងរំខានឬបញ្ជាក់អំឡុងពេលវេលាប៉ុន្តែមិនមានសមត្ថភាពដើម្បីបង្កើតប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនប


ឥឡូវនេះគឺជាពេលដើម្បីទទួលយកការពិតដែលយើងពិតជាត្រូវការឧបករណ៍ដែលមានជំនាញ។ ដូច្នេះឧបករណ៍របស់យើង -សត្វខ្ញុំបានក្លាយ

សត្វ

នៅកម្រិតខ្ពស់សកម្មភាពនៃ Swarm គឺដើម្បីចាប់ផ្តើមជាច្រើននៃអ្នកចូលរួមដែលនឹងផលិតការផ្ទុកនៅលើសេវាកម្ម។ អ្នកចូលរួមទាំងនេះត្រូវបានគេហៅថា bots ហើយពួកគេអាចរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការ


លក្ខណៈពិសេសនេះគឺដូច្នេះនៅទីនេះគឺជាសៀវភៅនៃតម្រូវការសម្រាប់ឧបករណ៍នេះ:


  1. ការឆ្លើយតបទៅនឹងការបច្ចុប្បន្នភាពរដ្ឋបាលគួរតែមានភាពងាយស្រួល
  2. ការប្រកួតប្រជែងមិនគួរតែជាបញ្ហា
  3. គោលបំណងគោលបំណងគោលបំណងគោលបំណង
  4. ការទំនាក់ទំនង bot-to-bot នឹងមានភាពងាយស្រួល
  5. លក្ខណៈសម្បត្តិផ្សេងគ្នានៅក្នុងការបង្កើតកម្រិតអតិបរមា
  6. ឧបករណ៍នេះគួរតែមានភាពងាយស្រួលនិងអាចបង្កើតសម្ពាធល្អនៅលើ backend របស់ខ្លួន។


ក្នុងនាមជាប្រាក់រង្វាន់ខ្ញុំបានបន្ថែមចំនួនបន្ថែមទៀត:

  1. ការធ្វើតេស្តកម្រិតខ្ពស់និងការធ្វើតេស្ត end-to-end នឹងអាចធ្វើបាន
  2. ឧបករណ៍នេះគួរតែជាការផ្លាស់ប្តូរ - agnostic; យើងគួរតែអាចផ្លាស់ប្តូរវាទៅនឹងការផ្លាស់ប្តូរផ្សេងទៀតដែលអាចធ្វើបានប្រសិនបើមានតម្រូវការ
  3. ឧបករណ៍នេះមានប្រភេទកូដ imperative ដូចជាខ្ញុំផ្ទាល់ខ្លួនមានអារម្មណ៍យ៉ាងខ្លាំងថាប្រភេទ declarative គឺមិនសមរម្យសម្រាប់ប្រវត្តិសាស្រ្តមានតម្រូវការដែលមានតម្រូវការ
  4. កុំព្យូទ័រគួរតែអាចមានតែមួយគត់ពីឧបករណ៍ធ្វើតេស្តដែលមានន័យថាមិនគួរតែមានការផ្លាស់ប្តូររឹងទេ។


គោលដៅរបស់យើង

សូមចង់រៀបចំនៃកូដដែលយើងចង់សរសេរ។ យើងនឹងគិតថា bot គឺជាបារាំងហើយវាមិនអាចធ្វើអ្វីបានដោយខ្លួនឯងប៉ុន្តែវាអាចរក្សាទុកការប្រែប្រែប្រែប៉ុណ្ណោះប៉ុន្តែ Scenario គឺជាបារាំងដែលបាត់បង់បារាំង។


public class ExampleScenario : ScenarioBase
{
    /* ... */
    public override async Task Run(ISwarmAgent swarm)
    {
        // spawn bots and connect to backend
        var leader = SpawnClient();
        var follower = SpawnClient();
        await leader.Login();
        await follower.Login();


        // expect incoming InviteAddedEvent
        var followerWaitingForInvite = follower.Group.Subscription
            .ListenOnceUntil(GroupInviteAdded)
            .ThrowIfTimeout();


        // leader sends invite and followers waits for it
        await leader.Group.SendGroupInvite(follower.PlayerId);
        await followerWaitingForInvite;
        Assert.That(follower.Group.State.IncomingInvites.Count, Is.EqualTo(1));
        var invite = follower.Group.State.IncomingInvites[0];


        // now vice versa, the leader waits for an event...
        var leaderWaitingForAccept = leader.Group.Subscription
            .ListenOnceUntil(InviteAcceptedBy(follower.PlayerId))
            .ThrowIfTimeout();


        // ... and follower accept invite, thus producing the event
        await follower.Group.AcceptGroupInvite(invite.Id);
        await leaderWaitingForAccept;
        Assert.That(follower.Group.State.GroupId, Is.EqualTo(leader.Group.State.GroupId));


        PlayerId[] expectedPlayers = [leader.PlayerId, follower.PlayerId];
        Assert.That(leader.Group.State.Players, Is.EquivalentTo(expectedPlayers));
        Assert.That(follower.Group.State.Players, Is.EquivalentTo(expectedPlayers));
    }
}


ដំបូង

ការផ្លាស់ប្តូរបច្ចុប្បន្នភាពជាច្រើនទៅដល់អតិថិជនដែលអាចកើតឡើងយ៉ាងឆាប់រហ័ស; នៅក្នុងឧទាហរណ៍ខាងលើ, ការប្រៀបធៀបនេះគឺGroupInviteAddedEventការធ្វើតេស្តនេះគួរតែមានសមត្ថភាពដើម្បីធ្វើតេស្តទាំងពីរទៅនឹងការធ្វើតេស្តទាំងនេះដោយផ្ទាល់ខ្លួននិងផ្តល់នូវឱកាសដើម្បីមើលពួកគេពីកូដខាងក្រៅ។


public Task SubscribeToGroupState()
{
   Subscription.Listen(OnGroupStateUpdate);
   Subscription.Start(api.GroupServiceClient.SubscribeToGroupStateUpdates, new SubscribeToGroupStateUpdatesRequest());
   return Task.CompletedTask;
}


ទោះបីជាកូដនេះគឺជាភាពងាយស្រួលណាស់ (និងដូចអ្នកអាចគិតថា)OnGroupStateUpdateប្រព័ន្ធ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ


StreamSubscriptionដោយខ្លួនឯង aIObservable<ObservedEvent<TStreamMessage>>

និងវាផ្តល់នូវការបន្ថែមដែលមានប្រសិទ្ធិភាព, មានប្រវែងជីវិតដែលមានគោលបំណង, និងត្រូវបានបណ្តុះបណ្តាលដោយគំនិត។

អត្ថប្រយោជន៍ផ្សេងទៀត: វាគឺជាការតម្រូវការការសន្សំដោយគ្មានការសន្សំដោយគ្មានការសរសេរឬការផ្លាស់ប្តូរស្ថានភាពដោយគ្មានការផ្លាស់ប្តូរកន្លែងដែលអ្នកដំណើរការត្រូវបានអនុវត្ត។


case GroupUpdateEventType.GroupInviteAddedEvent:
   State.IncomingInvites.Add(ev.GroupInviteAddedEvent.GroupId, ev.GroupInviteAddedEvent.Invite);
   break;


ការប្រកួតប្រជែងមិនគួរតែជាបញ្ហា

គំនិតនេះគឺជាការងាយស្រួល: ទោះជាយ៉ាងណាក៏ដោយមិនចាំបាច់អនុវត្តកូដដែលចូលរួមក្នុងប្រព័ន្ធប្រតិបត្តិការឬ bot ដែលត្រូវបានបង្កើតឡើងនៅក្នុងប្រព័ន្ធប្រតិបត្តិការនេះទេ។ លើសពីនេះទៀត, កូដខាងក្នុងសម្រាប់ bot / module នឹងមិនត្រូវបានអនុវត្តនៅពេលដែលផ្នែកផ្សេងទៀតនៃ bot ។


នេះគឺដូចជាការសរសេរ / សរសេរកូដដែលជាកូដសរសេរ (ការចូលរួម) និងកូដ bot ដែលជាការសរសេរ (ការចូលរួមតែមួយគត់) ហើយនៅពេលដែលគោលបំណងរបស់យើងអាចត្រូវបានទទួលបានដោយប្រើប្រភេទនៃកូដនេះមានវិធីល្អបំផុត។

ការរៀបចំនៃការធ្វើតេស្តនិងគំនិត synchronization

ការប្រៀបធៀបទាំងពីរដែលបានប្រៀបធៀបនៅក្នុងការប្រៀបធៀបនេះគឺជាផ្នែកដែលមានប្រសិទ្ធិភាពខ្លាំងណាស់នៃកូដ async នៅក្នុង C# ។ ប្រសិនបើអ្នកបានអភិវឌ្ឍកម្មវិធី WPF អ្នកអាចដឹងថាតើវាជាកម្មវិធីដែលមានប្រសិទ្ធិភាព។DispatcherSynchronizationContextវាគឺជាការគ្រប់គ្រងសម្រាប់ការផ្លាស់ប្តូរការទូរស័ព្ទ async របស់អ្នកទៅលើ UI thread ។


នៅក្នុងប្រវត្តិសាស្រ្តរបស់យើងយើងមិនចង់ចាប់អារម្មណ៍អំពីការរៀបចំនៃភ្នាល់ទេហើយជាផ្នែកមួយដែលយើងចង់ចាប់អារម្មណ៍អំពីដំណាក់កាលនៃការងារនៅក្នុងប្រវត្តិសាស្រ្តមួយ។


មុនពេលធ្វើការដើម្បីសរសេរកូដកម្រិតទាបសូមមើលកម្រិតមួយដែលមិនត្រូវបានគេស្គាល់យ៉ាងទូលំទូលំទូលាយConcurrentExclusiveSchedulerPairពី theដំណឹង:

ដំណឹង


អនុញ្ញាតឱ្យអ្នករៀបរៀបរៀបរៀបរៀបការដើម្បីដោះស្រាយកម្មវិធីក្នុងពេលដែលការធានាថានៅពេលដែលកម្មវិធីផ្សេងគ្នានេះអាចដោះស្រាយកម្មវិធីផ្សេងគ្នានិងកម្មវិធីផ្សេងគ្នានេះមិនអាចដោះស្រាយកម្មវិធី។

អនុញ្ញាតឱ្យអ្នករៀបរៀបរៀបរៀបរៀបការដើម្បីដោះស្រាយកម្មវិធីក្នុងពេលដែលការធានាថានៅពេលដែលកម្មវិធីផ្សេងគ្នានេះអាចដោះស្រាយកម្មវិធីផ្សេងគ្នានិងកម្មវិធីផ្សេងគ្នានេះមិនអាចដោះស្រាយកម្មវិធី។


នេះជាអ្វីដែលយើងចង់មើលឃើញ! ឥឡូវនេះយើងត្រូវការធ្វើឱ្យប្រាកដថាកូដទាំងអស់ក្នុងប្រព័ន្ធប្រតិបត្តិការនេះត្រូវបានដំណើរការនៅលើConcurrentSchedulerនៅពេលដែលកូដរបស់ bot បានអនុវត្តនៅលើExclusiveScheduler.


តើធ្វើដូចម្តេចដើម្បីកំណត់រចនាសម្ព័ន្ធសម្រាប់ការធ្វើតេស្តមួយ? ប្រភេទមួយគឺដើម្បីផ្ញើវាជាទំហំដោយពិសេសដែលធ្វើឡើងនៅពេលដែលប្រព័ន្ធប្រតិបត្តិការចាប់ផ្តើម:


public Task LaunchScenarioAsyncThread(SwarmAgent swarm, Launch launch)
{
   return Task.Factory.StartNew(
       () =>
       {
           /* <some observability and context preparations> */
           return RunScenarioInstance(Scenario, swarm, LaunchOptions, ScenarioActivity, launch);
       },
       CancellationToken.None,
       TaskCreationOptions.DenyChildAttach,
       Scenario.BotScenarioScheduler.ScenarioScheduler).Unwrap();
}


នេះRunScenarioInstanceគោលបំណងនេះបើយោងតាមគោលបំណងSetUpនិងRunប្រព័ន្ធ ប្រតិបត្តិការ iOS ប្រព័ន្ធ ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOS ប្រតិបត្តិការ iOSScenarioSchedulerជាផ្នែកមួយនៃការប្រកួតប្រជែងConcurrentExclusiveSchedulerPair) ។

ឥឡូវនេះ, នៅពេលដែលយើងមាននៅក្នុងកូដសិល្បៈនិងយើងធ្វើការនេះ ...


public Task LaunchScenarioAsyncThread(SwarmAgent swarm, Launch launch)
{
   return Task.Factory.StartNew(
       () =>
       {
           /* <some observability and context preparations> */
           return RunScenarioInstance(Scenario, swarm, LaunchOptions, ScenarioActivity, launch);
       },
       CancellationToken.None,
       TaskCreationOptions.DenyChildAttach,
       Scenario.BotScenarioScheduler.ScenarioScheduler).Unwrap();
}

...ម៉ាស៊ីន async បានធ្វើការងាររបស់ខ្លួនសម្រាប់យើងដោយការរក្សាទុកកំណត់សម្រាប់ការងាររបស់យើង។

ឥឡូវនេះSendGroupInviteវាត្រូវបានធ្វើឡើងនៅលើការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការ:


public Task<SendGroupInviteResponse> SendGroupInvite(PlayerId inviteePlayerId)
{
   return Runtime.Do(async () =>
   {
       var result = await api.GroupServiceClient.SendGroupInviteAsync(/* ... */);
       if (!result.HasError)
       {
           State.OutgoingInvites.Add(inviteePlayerId);
       }


       return result;
   });
}


ការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការTask.Factory.StartNewជាមួយនឹងកំណត់ដំណឹងល្អ។

លេខកូដ

OK, ឥឡូវនេះយើងត្រូវការកាត់បន្ថយអ្វីគ្រប់យ៉ាងក្នុងខាងក្នុងDoទូរស័ព្ទ; ហើយប៉ុន្តែវាបានដោះស្រាយបញ្ហានេះ, វាមានអត្ថប្រយោជន៍ក្នុងការបាត់បង់យ៉ាងងាយស្រួល, និងជាទូទៅវាជាការគួរឱ្យស្រស់ស្អាត។

សូមមើលផ្នែកនេះនៃកូដមួយទៀត:


await leader.Group.SendGroupInvite(follower.PlayerId);


នៅទីនេះ, bot របស់យើងមាន aGroupសមត្ថភាពGroupនេះគឺជាម៉ូឌុលដែលមានតែដើម្បីផ្លាស់ប្តូរកូដទៅជាកម្រិតផ្សេងគ្នានិងការពារពីការបំពាក់កូដ។Botសត្វ។


public class BotClient : BotClientBase
{
    public GroupBotModule Group { get; }
    /* ... */
}


សូមប្រាកដថា ម៉ូឌុលគួរតែមានអ៊ីនធឺណិត:


public class BotClient : BotClientBase
{
    public IGroupBotModule Group { get; }
    /* ... */
}


public interface IGroupBotModule : IBotModule, IAsyncDisposable
{
    GroupBotState State { get; }


    Task<SendGroupInviteResponse> SendGroupInvite(PlayerId toPlayerId);
    /* ... */
}




public class GroupBotModule :
   BotClientModuleBase<GroupBotModule>,
   IGroupBotModule
{
    /* ... */
    public async Task<SendGroupInviteResponse> SendGroupInvite(PlayerId inviteePlayerId)
    {
        // no wrapping with `Runtime.Do` here
        var result = await api.GroupServiceClient.SendGroupInviteAsync(new() /* ... */);
        if (!result.HasError)
        {
            State.OutgoingInvites.Add(new GroupBotState.Invite(inviteePlayerId, /* ... */));
        }


        return result;
   }
|


ហើយឥឡូវនេះវាតែធ្វើការ! មិនមែនជាកូដធ្លាក់ចុះនិងធ្លាក់ចុះទេប៉ុន្តែគ្រាន់តែជាតម្រូវការងាយស្រួល (ដែលជាធម្មតាសម្រាប់អ្នកអភិវឌ្ឍន៍) ដើម្បីបង្កើតអ៊ីនធឺណិតសម្រាប់ម៉ូឌុលទាំងអស់។


ទោះជាយ៉ាងណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏ដោយវាជាការពិតណាក៏។Runtime.Doទូរស័ព្ទ :


   public const string MethodProxy =
@"
   public async $return_type$ $method_name$($method_params$)
   {
       $return$await runtime.Do(() => implementation.$method_name$($method_args$));
   }
";


ឧបករណ៍

ជំហានបន្ទាប់នេះគឺដើម្បីឧបករណ៍កូដដើម្បីជួបប្រជុំគ្នានិងតម្រូវការ។ ជាលើកដំបូង, ទាំងអស់នៃការទូរស័ព្ទ API នេះគួរតែត្រូវបានពិនិត្យឡើងវិញ។ ការផ្លាស់ប្តូរនេះគឺយ៉ាងងាយស្រួលជាការដឹកជញ្ជូនរបស់យើងមានប្រសិទ្ធិភាពធ្វើឱ្យប្រាកដថាជាប្រព័ន្ធ gRPC ដូច្នេះយើងគ្រាន់តែប្រើ interceptor ដែលបានសរសេរយ៉ាងត្រឹមត្រូវ...


callInvoker = channel
   .Intercept(new PerformanceInterceptor());


កន្លែងដែលCallInvokerវាគឺជាការបង្វិល gRPC នៃការបង្វិល RPC របស់អតិថិជន។


បន្ទាប់មកវាគឺជាការល្អប្រសើរណាស់ដើម្បីកំណត់ផ្នែកមួយចំនួននៃកូដដើម្បីត្រួតពិនិត្យការអនុវត្ត។ ដូច្នេះគ្រប់ម៉ូដទាំងអស់ injectsIInstrumentationFactoryជាមួយនឹងអ៊ីនធឺណិតខាងក្រោម:


public interface IInstrumentationFactory

{

   public IInstrumentationScope CreateScope(

       string? name = null,

       IInstrumentationContext? actor = null,

       [CallerMemberName] string memberName = "",

       [CallerFilePath] string sourceFilePath = "",

       [CallerLineNumber] int sourceLineNumber = 0);

}


ឥឡូវនេះអ្នកអាចបំពាក់ផ្នែកដែលអ្នកមានអារម្មណ៍នៅក្នុង:


public Task AcceptGroupInvite(GroupInvideId inviteId)
{
    using (instrumentationFactory.CreateScope())
    {
        var result = await api.GroupServiceClient.AcceptGroupInviteAsync(request);
    }
}


ប្រសិនបើអ្នកអាចប្រើលក្ខណៈពិសេសនេះដើម្បីបង្កើតតំបន់បណ្ដាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញបណ្តាញ


   public const string MethodProxy =
@"
   public async $return_type$ $method_name$($method_params$)
   {
       using(instrumentationFactory.CreateScope(/* related args> */))
       {
           $return$await runtime.Do(() => implementation.$method_name$($method_args$));
       }
   }
";


ទំហំឧបករណ៍បានចុះឈ្មោះពេលវេលាការដោះស្រាយការប៉ុណ្ណោះបានបង្កើតដំណោះស្រាយចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយដំណោះស្រាយផ្សេងទៀត។


ការផ្សព្វផ្សាយ bot-to-bot

គំរូនៅក្នុងតំបន់ "គោលបំណងរបស់យើង" មិនបង្ហាញអំពីការទំនាក់ទំនងទេ។ យើងគ្រាន់តែដឹងអំពី bot របស់អ្នកគាំទ្រ។PlayerIdទោះបីជាប្រភេទនេះនៃការសរសេរប្រសិនបើមានភាពងាយស្រួលនិងស្រស់ស្អាតនោះទេប៉ុន្តែមានប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រស


ខ្ញុំនៅដំបូងខ្ញុំមានគោលបំណងដើម្បីអនុវត្តប្រភេទមួយនៃគំរូ blackboard ជាមួយនឹងការផ្ទុកគោលបំណងគោលបំណងសម្រាប់ការទំនាក់ទំនង (ដូចជា Redis) ប៉ុន្តែបន្ទាប់ពីការធ្វើតេស្តគំនិតគោលបំណងមួយចំនួនបានបង្ហាញថាការធ្វើតេស្តអាចត្រូវបានកាត់បន្ថយយ៉ាងខ្លាំងទៅនឹងគោលបំណងពីរដែលមានភាពងាយស្រួលជាងមុន: ជម្រើសនិងអ្នកជ្រើស។

យោបល់ - Tickets

នៅលើពិភពលោកពិតប្រាកដអ្នកលេងផ្លាស់ប្តូរជាមួយគ្នា - ពួកគេបានសរសេរសេចក្តីអធិប្បាយដោយផ្ទាល់ឬប្រើការសរសេរភ្ញាក់ផ្លាស់ប្តូរដោយភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់ផ្លាស់ប្តូរភ្ញាក់មនុស្សសូមអរគុណអ្នកដើម្បីចូលទៅក្នុងក្រុមរបស់ខ្ញុំ។ នៅទីនេះជាទីតាំងដែលសំបុត្រចូលទៅក្នុងការប្រកួត:


public interface ISwarmTickets
{
   Task PlaceTicket(SwarmTicketBase ticket);


   Task<SwarmTicketBase?> TryGetTicket(Type ticketType, TimeSpan timeout);
}


កុំព្យូទ័រនេះអាចដំឡើងកុំព្យូទ័រមួយហើយបន្ទាប់មកកុំព្យូទ័រមួយផ្សេងទៀតអាចទាញយកកុំព្យូទ័រនេះ។ISwarmTicketsមិនមែនជាមិត្តភក្តិមិត្តភក្តិមិត្តភក្តិមិត្តភក្តិមិត្តភក្តិមិត្តភក្តិticketType(បច្ចុប្បន្ននេះគឺជាសត្វច្រើនជាងនេះ, ដូច្នេះមានលក្ខណៈពិសេសបន្ថែមទៀតដើម្បីជួសជុល bots ពីការស្វែងរកតុល្យភាពរបស់ពួកគេដូចជាការធ្វើតេស្តតូចផ្សេងទៀត។


ជាមួយនឹងអ៊ីនធឺណិតនេះយើងអាចផ្លាស់ប្តូរប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រសិនបើប្រ


private async Task RunLeaderRole(ISwarmAgent swarm)
{
   var ticket = await swarm.Blackboard.Tickets
       .TryGetTicket<BotWantsGroupTicket>(TimeSpan.FromSeconds(5))
       .ThrowIfTicketIsNull();


   await bot.Group.SendGroupInvite(ticket.Owner);
   await bot.Group.Subscription.ListenOnceUntil(
           GotInviteAcceptedEvent,
           TimeSpan.FromSeconds(5))
       .ThrowIfTimeout();
}


private async Task RunFollowerRole(ISwarmAgent swarm)
{
   var waitingForInvite = bot.Group.Subscription.ListenOnceUntil(
           GotInviteAddedEvent,
           TimeSpan.FromSeconds(5))
       .ThrowIfTimeout();


   await swarm.Blackboard.Tickets.PlaceTicket(new BotWantsGroupTicket(bot.PlayerId));
   await waitingForInvite;
   await bot.Group.AcceptGroupInvite(bot.Group.State.IncomingInvites[0].Id);
}


ជ្រើសរើស

យើងមានដំណោះស្រាយពីរដំណោះស្រាយមួយសម្រាប់អ្នកគ្រប់គ្រងមួយសម្រាប់អ្នកគ្រប់គ្រងមួយសម្រាប់អ្នកគ្រប់គ្រងមួយ។ ដូចគ្នានេះវាអាចត្រូវបានផ្លាស់ប្តូរទៅក្នុងដំណោះស្រាយពីរដំណោះស្រាយផ្សេងគ្នានិងចាប់ផ្តើមតាមដំណោះស្រាយ។ ពេលវេលានេះគឺជាវិធីល្អបំផុតដើម្បីធ្វើដូច្នេះ, ពេលវេលាផ្សេងទៀតអ្នកអាចត្រូវការកំណត់ដំណោះស្រាយនៃទំហំក្រុម (អ្នកគ្រប់គ្រងជាច្រើនក្នុងមួយអ្នកគ្រប់គ្រងមួយ) ឬប្រព័ន្ធផ្សេងទៀតដើម្បីផ្លាស់ប្តូរ / ជ្រើសរើសទិន្នន័យ / ដំណោះស្រាយផ្សេងគ្នា។


public override async Task Run(ISwarmAgent swarm)
{
   var roleAction = await swarm.Blackboard
       .RoundRobinRole(
           "leader or follower",
           Enumerable.Repeat(RunFollowerRole, config.GroupSize - 1).Union([RunLeaderRole]));
   await roleAction(swarm);
}


នៅទីនេះRoundRobinRoleវាគឺគ្រាន់តែជាការវេចខ្ចប់ស្រស់ស្អាតនៅជុំវិញការគណនានិងប្រតិបត្តិការ modulo ដើម្បីជ្រើសរើសអ៊ីម៉ែលត្រឹមត្រូវពីគណិត។


សត្វ Swarms

ឥឡូវនេះ, ជាមួយនឹងការទំនាក់ទំនងទាំងអស់ដែលត្រូវបានចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែកចែក


គោលបំណងដ៏អស្ចារ្យ: យើងមិនបានបញ្ចប់ការអនុវត្តនៃលក្ខណៈនេះទេ។ នៅពេលដែល QA បានទទួលបានការអនុវត្តរបស់ពួកគេនៅលើកុងតែមួយ SwarmAgentនៅពេលដែលពួកគេបានចាប់ផ្តើមចាប់ផ្តើមរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀបរៀប

ការអនុវត្តតែមួយ

តើធ្វើដូចម្តេចអំពីការធ្វើឱ្យប្រសើរឡើង? តើមានអ្វីដែលត្រូវបានបាត់បង់នៅក្នុងការវេចខ្ចប់ទាំងអស់និងការត្រួតពិនិត្យគ្នានៃការគិតថ្លៃ? ខ្ញុំមិននឹងបាត់បង់អ្នកជាមួយនឹងការធ្វើតេស្តផ្សេងៗទាំងអស់ដែលបានធ្វើឡើង, គ្រាន់តែពីរនៃការសំខាន់បំផុតដែលបានបង្ហាញថាប្រព័ន្ធនេះអាចបង្កើតផ្ទុកល្អឥតខ្ចោះ។

ការបង្កើត Benchmark:

BenchmarkDotNet v0.14.0, ប្រព័ន្ធប្រតិបត្តិការ Windows 10 (10.0.19045.4651/22H2/2022Update)
Intel Core i7-10875H CPU 2.30GHz, 1 CPU, 16 គោលនយោបាយនិង 8 គោលនយោបាយ
ប្រព័ន្ធប្រតិបត្តិការ .NET SDK 9.0.203
ប្រព័ន្ធ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ
ប្រព័ន្ធ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ


private async Task SimpleWorker()
{
   var tasks = new List<Task>();
   for (var i = 0; i < Parallelism; ++i)
   {
       var index = i;
       tasks.Add(Task.Run(async () =>
       {
           for (var j = 0; j < Iterations; ++j)
           {
               await LoadMethod(index);
           }
       }));
   }


   await Task.WhenAll(tasks);
}


private async Task SchedulerWorker()
{
    // scenarios are prepared in GlobalSetup
    await Task.WhenAll(scenarios.Select(LaunchScenarioAsyncThread));
}


public class TestScenario : ScenarioBase
{
    public override async Task Run()
    {
        for (var iteration = 0; iteration < iterations; ++iteration)
        {
            await botClient.Do(BotLoadMethod);
        }
    }
}


សូមពិនិត្យឡើងវិញពីការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំនៃការរៀបចំ។

ក្នុងករណីនេះវិធីសាស្រ្តផ្ទុកទាំងពីរគឺដូចខាងក្រោម:


private ValueTask CounterLoadMethod(int i)

{

   Interlocked.Increment(ref StaticControl.Counter);

   return ValueTask.CompletedTask;

}


លទ្ធផលសម្រាប់ Iterations = 10:

WorkerType

Parallelism

Mean

Error

StdDev

Gen0

Gen1

Gen2

Allocated

Simple

10

3.565us

0.0450us

0.0421us

0.3433

-

-

2.83KB

Simple

100

30.281us

0.2720us

0.2544us

3.1128

0.061

-

25.67KB

Simple

1000

250.693us

2.1626us

2.4037us

30.2734

5.8594

-

250.67KB

Scheduler

10

40.629us

0.7842us

0.8054us

8.1787

0.1221

-

66.15KB

Scheduler

100

325.386us

2.3414us

2.1901us

81.0547

14.6484

-

662.09KB

Scheduler

1000

4,685.812us

24.7917us

21.9772us

812.5

375

-

6617.59KB

ដំបូង

10

565 លទ្ធផល

លទ្ធផល 0.0450

00421 លទ្ធផល

0.3433

-

-

8.8 គីឡូក្រាម

ដំបូង

100

លទ្ធផល 281

0.2720 លទ្ធផល

0.2544us

3.1128

0.061

-

2567 គីឡូក្រាម

ដំបូង

1000

លក្ខណៈពិសេស

1626 មីនាទី

2.4037 លទ្ធផល

30.2734

5.8594

-

250.67 គីឡូក្រាម

សកម្មភាព

10

លទ្ធផល 629

លទ្ធផល 7842

លទ្ធផល 8054

8.1787

0.1221

-

615 គីឡូក្រាម

សកម្មភាព

100

លទ្ធផល 386

2.3414 អាសយដ្ឋាន

2 ឆ្នាំ 1901

81.0547

14.6484

-

លក្ខណៈពិសេស

សកម្មភាព

1000

លក្ខណៈពិសេស

7277 អាសយដ្ឋាន

9277 អាសយដ្ឋាន

812.5

375

-

លក្ខណៈពិសេស



តើធ្វើដូចម្តេច? មិនត្រឹមត្រូវទេ។ មុនពេលធ្វើការធ្វើការសាកល្បងពិតប្រាកដខ្ញុំគិតថាការធ្វើការប្រសើរជាងមុនទេប៉ុន្តែផលិតផលពិតប្រាកដថាខ្ញុំបានសាកល្បងទេ។ សូមគិតអំពីអ្វីដែលបានធ្វើឡើងនៅក្រោមការសាកល្បងនិងអត្ថប្រយោជន៍ដែលយើងបានទទួលបានតែសម្រាប់ ~4us ក្នុងមួយប្រវត្តិសាស្រ្តដទៃ។ ដូច្នេះវាគឺជាការបង្ហាញតែមួយនៃការប្រសើរឡើងវិញ។ យើងមានអារម្មណ៍ក្នុងគោលបំណងបន្ថែមទៀត។


អ្វីដែលអាចជាប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រស


ប្រព័ន្ធ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការ ប្រតិបត្តិការPingAsyncសម្រាប់ភាពងាយស្រួលរបស់យើង, RPC client ដែលត្រូវបានរក្សាទុកនៅខាងក្រៅនៃ bots ។


private async ValueTask PingLoadMethod(int i)
{
   await clients[i].PingAsync(new PingRequest());
}


Here are the results, again 10 iterations (server grpc គឺនៅក្នុងបណ្តាញផ្ទាល់ខ្លួន):


WorkerType

Parallelism

Mean

Error

StdDev

Gen0

Gen1

Allocated

Simple

100

94.45 ms

1.804 ms

2.148 ms

600

200

6.14 MB

Simple

1000

596.69 ms

15.592 ms

45.730 ms

9000

7000

76.77 MB

Scheduler

100

95.48 ms

1.547 ms

1.292 ms

833.3333

333.3333

6.85 MB

Scheduler

1000

625.52 ms

14.697 ms

42.405 ms

8000

7000

68.57 MB

ដំបូង

100

លក្ខណៈពិសេស 94.45 ms

804 មីនាទី

284 មីនាទី

600

200

6.14 មេកាបៃ

ដំបូង

1000

69.69 មីនាទី

15 592 មីនាទី

45730 មីនាទី

9000

7000

767 មេកាបៃ

សកម្មភាព

100

95.48 មីនាទី

1547 គីឡូក្រាម

1,292 មីនាទី

833.3333

333.3333

6.85 មេកាបៃ

សកម្មភាព

1000

625 គីឡូក្រាម

14.697 មីនាទី

4405 មីនាទី

8000

7000

លក្ខណៈសម្បត្តិ 68.57 MB


ដូចគ្នានៅពេលដែលគួរឱ្យចាប់អារម្មណ៍ថានៅពេលដែលផលប៉ះពាល់នៃការធ្វើឱ្យប្រសើរឡើងដល់ប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមានប្រសិនបើមាន។


ការពិនិត្យ

លក្ខណៈពិសេសរបស់ Swarm គឺជាការពិតប្រាកដដែលអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកអាចធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិនបើអ្នកធ្វើឱ្យប្រសិន


នេះគឺជាឧទាហរណ៍នៃគំរូផ្សេងគ្នានៅក្នុងការធ្វើតេស្តបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានៃការបញ្ហានរបស់អ្នក។


Grafana dashboard panels showing failed test


យើងជាធម្មតាត្រូវបានកាត់បន្ថយការធ្វើតេស្តយ៉ាងពេញលេញបន្ទាប់ពីបញ្ហាសម្រាប់ចំនួនមួយចំនួននៃបញ្ហាសម្រាប់ការធ្វើតេស្តនេះ, ដូច្នេះការទូរស័ព្ទ API បានបញ្ចប់យ៉ាងឆាប់រហ័ស។


លក្ខណៈពិសេសនៃការធ្វើតេស្ត Swarm គឺជាលក្ខណៈពិសេសនៃការធ្វើតេស្ត Swarm ។ សម្រាប់ការធ្វើតេស្ត Swarm, លក្ខណៈពិសេសនៃការធ្វើតេស្ត Swarm គឺជាលក្ខណៈពិសេសនៃការធ្វើតេស្ត Swarm ។connectionIdD/botIdអ្វីដែលបានជួយក្នុងការ debugging ។


Distributed tracing connecting Swarm scenario with backend


Note: DevServer គឺជាការសាងសង់ monolith ដែលមានភាពងាយស្រួលនៃសេវាកម្ម backend ទាំងអស់នៅក្នុងមួយដែលនឹងត្រូវបានបើកដំណើរការនៅលើកុំព្យូទ័រអ្នកអភិវឌ្ឍន៍ហើយវាគឺជាឧទាហរណ៍ដែលត្រូវបានរចនាឡើងជាពិសេសដើម្បីកាត់បន្ថយទំហំនៃទិន្នន័យនៅលើអេក្រង់។


Swarm bots បានសរសេរប្រភេទផ្សេងទៀតនៃដំណាក់កាល: ពួកគេបានសរសេរដំណាក់កាលដែលត្រូវបានប្រើក្នុងការដំណាក់កាលដែលមានប្រសិទ្ធិភាព។ ជាមួយនឹងការជួយនៃឧបករណ៍ដែលមានប្រសិទ្ធិភាពអាចមើលនិងវិភាគដំណាក់កាលទាំងនេះដោយប្រើសមត្ថភាពដែលមានមូលដ្ឋានដូចជា PerfettoSQL ។


Adapting perf logs to show bot execution flow

អ្វីដែលយើងបានបញ្ចប់នៅចុងក្រោយ

ឥឡូវនេះយើងមាន SDK ដែលបំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់បំពង់


ការអាចសរសេរកូដដែលមានភាពងាយស្រួលបានអនុញ្ញាតឱ្យក្រុម QA បានបង្កើតម៉ូឌុលថ្មីនិងប្រវត្តិសាស្រ្តធ្វើតេស្តដែលមានភាពងាយស្រួល។ មានគំនិតអំពីប្រវត្តិសាស្រ្ត FlowGraph (កម្មវិធីរចនាសម្ព័ន្ធរូបភាព) ប៉ុន្តែវាមានគំនិតតែប៉ុណ្ណោះនៅពេលនេះ។


ការធ្វើតេស្តប្រសិទ្ធិភាពគឺជាការរំខាន - ខ្ញុំបាននិយាយយ៉ាងហោចណាស់ដោយសារតែអ្នកគួរតែចាប់ផ្តើមពួកគេដោយផ្ទាល់។


Swarm មិនគ្រាន់តែជួយជាមួយនឹងការធ្វើតេស្តទេប៉ុន្តែវាត្រូវបានប្រើជាធម្មតានៅក្នុងការធ្វើតេស្តនិងដោះស្រាយបញ្ហានៅក្នុងការលេងហ្គេម, ជាពិសេសនៅពេលដែលការធ្វើតេស្តនេះមានភាពងាយស្រួលក្នុងការធ្វើតេស្តដោយដៃដូចជាពេលដែលអ្នកត្រូវការអតិថិជនជាច្រើនក្នុងការធ្វើតេស្តឯកទេស។


សូមបញ្ជាក់ថាយើងមានអារម្មណ៍ខ្លាំងណាស់អំពីការធ្វើតេស្តរបស់យើងហើយយើងមិនមានអារម្មណ៍អំពីការធ្វើតេស្តរបស់យើង។



ខ្ញុំចង់ឱ្យអ្នករីករាយជាមួយសៀវភៅនេះ, វាគឺជាការជោគជ័យដើម្បីបង្ហាញអ្នកអំពីការអភិវឌ្ឍន៍ Swarm ទាំងអស់ដោយមិនធ្វើឱ្យសៀវភៅនេះបានបំបែកយ៉ាងខ្លាំង។ ខ្ញុំមានសុវត្ថិភាពថាខ្ញុំអាចបាត់បន្ថយព័ត៌មានសំខាន់មួយចំនួននៅក្នុងដំណើរការនៃការកំណត់ទំហំសៀវភៅនិងព័ត៌មានប៉ុន្តែខ្ញុំនឹងផ្តល់ឱ្យអ្នកនូវអារម្មណ៍បន្ថែមទៀតប្រសិនបើអ្នកមានសំណួរណាមួយ!

L O A D I N G
. . . comments & more!

About Author

ព្យួរស្លាក

អត្ថបទនេះត្រូវបានបង្ហាញនៅក្នុង...

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks