เหตุใดฟังก์ชันทั้งหมดจึงไม่ควรเป็น async ตามค่าเริ่มต้น


107

async-รอคอยรูปแบบของสุทธิ 4.5 มีการเปลี่ยนแปลงกระบวนทัศน์ เกือบจะดีเกินไปที่จะเป็นจริง

ฉันได้ย้ายรหัส IO-heavy ไปยัง async-await เพราะการบล็อกเป็นเรื่องในอดีต

มีคนไม่กี่คนที่เปรียบเทียบ async-await กับ zombie infestation และฉันพบว่ามันค่อนข้างแม่นยำ รหัส Async ชอบรหัส async อื่น ๆ (คุณต้องมีฟังก์ชัน async เพื่อรอฟังก์ชัน async) ฟังก์ชันที่มากขึ้นเรื่อย ๆ จึงกลายเป็น async และสิ่งนี้จะเติบโตขึ้นเรื่อย ๆ ใน codebase ของคุณ

การเปลี่ยนฟังก์ชั่นเป็น async ค่อนข้างซ้ำซากและไม่น่าแปลกใจ โยนasyncคีย์เวิร์ดในการประกาศตัดค่าส่งคืนTask<>และคุณก็ทำได้สำเร็จ มันค่อนข้างจะไม่มั่นคงว่ากระบวนการทั้งหมดนั้นง่ายเพียงใดและในไม่ช้าสคริปต์การแทนที่ข้อความจะทำให้ "การย้าย" ส่วนใหญ่เป็นไปโดยอัตโนมัติ

และตอนนี้คำถาม .. ถ้าโค้ดทั้งหมดของฉันค่อยๆเปลี่ยน async ทำไมไม่ทำให้ async ทั้งหมดเป็นค่าเริ่มต้นล่ะ

เหตุผลที่ชัดเจนที่ฉันคิดคือประสิทธิภาพ Async-await มีค่าใช้จ่ายและรหัสที่ไม่จำเป็นต้องเป็นแบบ async ไม่ควร แต่หากประสิทธิภาพเป็นปัญหาเพียงอย่างเดียวการเพิ่มประสิทธิภาพที่ชาญฉลาดบางอย่างสามารถลบค่าใช้จ่ายโดยอัตโนมัติเมื่อไม่จำเป็น ฉันได้อ่านเกี่ยวกับการเพิ่มประสิทธิภาพ"เส้นทางที่รวดเร็ว"และสำหรับฉันแล้วฉันคิดว่าการเพิ่มประสิทธิภาพเพียงอย่างเดียวควรดูแลส่วนใหญ่

บางทีสิ่งนี้อาจเทียบได้กับการปรับเปลี่ยนกระบวนทัศน์ที่เกิดจากคนเก็บขยะ ในช่วงแรกของ GC การเพิ่มหน่วยความจำของคุณเองนั้นมีประสิทธิภาพมากขึ้นอย่างแน่นอน แต่คนจำนวนมากยังคงเลือกการรวบรวมอัตโนมัติเพื่อสนับสนุนรหัสที่ปลอดภัยและง่ายกว่าซึ่งอาจมีประสิทธิภาพน้อยกว่า (และเนื้อหานั้นก็ไม่เป็นความจริงอีกต่อไป) อาจจะเป็นกรณีนี้? เหตุใดฟังก์ชันทั้งหมดจึงไม่ควรเป็นแบบ async


8
ให้เครดิตทีม C # ในการทำเครื่องหมายบนแผนที่ เหมือนที่เคยทำเมื่อหลายร้อยปีก่อน "มังกรนอนอยู่ที่นี่" คุณสามารถจัดเตรียมเรือและไปที่นั่นได้ซึ่งน่าจะเป็นไปได้ว่าคุณจะรอดชีวิตได้โดยมีดวงอาทิตย์ส่องแสงและมีลมอยู่ด้านหลังของคุณ และบางครั้งไม่พวกเขาไม่เคยกลับมา เช่นเดียวกับ async / await SO เต็มไปด้วยคำถามจากผู้ใช้ที่ไม่เข้าใจว่าพวกเขาออกจากแผนที่ได้อย่างไร แม้ว่าพวกเขาจะได้รับคำเตือนที่ดีงาม ตอนนี้มันเป็นปัญหาของพวกเขาไม่ใช่ปัญหาของทีม C # พวกเขาทำเครื่องหมายมังกร
Hans Passant

1
@ บอกว่าแม้ว่าคุณจะลบความแตกต่างระหว่างฟังก์ชันซิงค์และ async ออกไปฟังก์ชันการโทรที่ใช้งานแบบซิงโครนัสจะยังคงเป็นแบบซิงโครนัส (เช่นตัวอย่าง WriteLine ของคุณ)
talkol

2
“ ตัดค่าส่งคืนตามงาน <>” เว้นแต่ว่าวิธีของคุณจะต้องเป็นasync(เพื่อให้เป็นไปตามสัญญา) นี่อาจเป็นความคิดที่ไม่ดี คุณได้รับข้อเสียของ async (ค่าใช้จ่ายในการเรียกเมธอดเพิ่มขึ้นความจำเป็นในการใช้awaitรหัสการโทร) แต่ไม่มีข้อดี
svick

1
นี่เป็นคำถามที่น่าสนใจจริงๆ แต่อาจจะไม่เหมาะกับ SO เราอาจพิจารณาย้ายข้อมูลไปยังโปรแกรมเมอร์
Eric Lippert

1
บางทีฉันอาจจะขาดอะไรไป แต่ฉันก็มีคำถามเหมือนกัน หาก async / await มาเป็นคู่เสมอและโค้ดยังคงต้องรอให้มันดำเนินการเสร็จสิ้นทำไมไม่เพียงแค่อัปเดตกรอบงาน. NET ที่มีอยู่และทำให้เมธอดเหล่านั้นต้องเป็น async - async ตามค่าเริ่มต้นโดยไม่ต้องสร้างคำหลักเพิ่มเติม? ภาษากำลังกลายเป็นสิ่งที่ออกแบบมาเพื่อหลีกเลี่ยง - คำหลักสปาเก็ตตี้ ฉันคิดว่าพวกเขาควรจะหยุดทำเช่นนั้นหลังจากที่มีการแนะนำ "var" ตอนนี้เรามี "dynamic", asyn / await ... etc ... ทำไมพวกคุณไม่แค่จาวาสคริปต์. NET-ify? ;))
monstro

คำตอบ:


127

ก่อนอื่นขอขอบคุณสำหรับคำพูดที่ดีของคุณ มันเป็นคุณสมบัติที่ยอดเยี่ยมจริงๆและฉันดีใจที่ได้เป็นส่วนเล็ก ๆ ของมัน

หากรหัสทั้งหมดของฉันเปลี่ยนเป็น async อย่างช้าๆทำไมไม่ทำให้ async ทั้งหมดเป็นค่าเริ่มต้น

คุณพูดเกินจริง รหัสทั้งหมดของคุณไม่เปลี่ยนเป็น async เมื่อคุณบวกจำนวนเต็ม "ธรรมดา" สองตัวเข้าด้วยกันคุณจะไม่รอผลลัพธ์ เมื่อคุณบวกจำนวนเต็มในอนาคตสองจำนวนเข้าด้วยกันเพื่อให้ได้จำนวนเต็มในอนาคตที่สามเพราะนั่นTask<int>คือจำนวนเต็มที่คุณจะสามารถเข้าถึงได้ในอนาคตแน่นอนว่าคุณอาจกำลังรอผลลัพธ์อยู่

เหตุผลหลักที่ไม่ทำให้ทุกอย่าง async เป็นเพราะจุดประสงค์ของ async / await คือทำให้ง่ายต่อการเขียนโค้ดในโลกที่มีการดำเนินการแฝงสูงมากมาย การดำเนินการส่วนใหญ่ของคุณไม่ใช่เวลาในการตอบสนองที่สูงดังนั้นจึงไม่สมเหตุสมผลที่จะใช้ผลการดำเนินงานที่ช่วยลดความหน่วงนั้น แต่การดำเนินการที่สำคัญบางประการของคุณมีความหน่วงแฝงสูงและการดำเนินการเหล่านั้นทำให้ซอมบี้แพร่ระบาดของ async ตลอดทั้งรหัส

หากประสิทธิภาพเป็นปัญหาเดียวแน่นอนว่าการเพิ่มประสิทธิภาพที่ชาญฉลาดบางอย่างสามารถลบค่าโสหุ้ยได้โดยอัตโนมัติเมื่อไม่จำเป็น

ในทางทฤษฎีทฤษฎีและการปฏิบัติมีความคล้ายคลึงกัน ในทางปฏิบัติพวกเขาไม่เคยเป็น

ผมขอให้สามคะแนนกับการเปลี่ยนแปลงประเภทนี้ตามด้วยการเพิ่มประสิทธิภาพ

จุดแรกอีกครั้งคือ async ใน C # / VB / F # โดยพื้นฐานแล้วเป็นการส่งผ่านความต่อเนื่องที่จำกัด งานวิจัยจำนวนมหาศาลในชุมชนภาษาที่ใช้งานได้ได้ค้นหาวิธีการระบุวิธีเพิ่มประสิทธิภาพโค้ดที่ใช้รูปแบบการส่งผ่านความต่อเนื่องอย่างหนัก ทีมคอมไพเลอร์น่าจะต้องแก้ปัญหาที่คล้ายกันมากในโลกที่ "async" เป็นค่าเริ่มต้นและต้องระบุวิธีการที่ไม่ใช่ async และ de-async-ified ทีม C # ไม่สนใจที่จะแก้ปัญหาการวิจัยแบบเปิดดังนั้นจึงเป็นประเด็นสำคัญที่ตรงนั้น

ประเด็นที่สองคือ C # ไม่มีระดับ "ความโปร่งใสในการอ้างอิง" ที่ทำให้การเพิ่มประสิทธิภาพประเภทนี้สามารถดึงข้อมูลได้มากขึ้น โดย "อ้างอิงความโปร่งใส" ผมหมายถึงทรัพย์สินที่มูลค่าของการแสดงออกไม่ได้ขึ้นอยู่กับเมื่อมันได้รับการประเมิน การแสดงออกเช่น2 + 2มีความโปร่งใสอ้างอิง คุณสามารถทำการประเมินผลในเวลาคอมไพล์ได้หากต้องการหรือเลื่อนออกไปจนกว่าจะรันไทม์และได้รับคำตอบเดียวกัน แต่การแสดงออกเช่นx+yไม่สามารถย้ายไปรอบ ๆ ในเวลาเพราะx และ y อาจจะมีการเปลี่ยนแปลงอยู่ตลอดเวลา

Async ทำให้ยากขึ้นมากที่จะหาเหตุผลว่าผลข้างเคียงจะเกิดขึ้นเมื่อใด ก่อน async ถ้าคุณพูดว่า:

M();
N();

และM()เป็นvoid M() { Q(); R(); }และN()เป็นvoid N() { S(); T(); }และRและSก่อให้เกิดผลข้างเคียงคุณจะรู้ว่าผลข้างเคียงของ R เกิดขึ้นก่อนผลข้างเคียงของ S แต่ถ้าคุณมีasync void M() { await Q(); R(); }แล้วจู่ๆก็ออกไปนอกหน้าต่าง คุณไม่สามารถรับประกันได้ว่าR()จะเกิดขึ้นก่อนหรือหลังS()(เว้นแต่M()จะมีการรอคอยแน่นอน แต่แน่นอนว่าTaskไม่จำเป็นต้องรอจนกว่าจะถึงภายหลังN())

ตอนนี้คิดว่าทรัพย์สินนี้ไม่ทราบว่าสิ่งที่ผลข้างเคียงที่เกิดขึ้นในการสั่งซื้อนำไปใช้กับชิ้นส่วนของรหัสในโปรแกรมของคุณทุกคนยกเว้นผู้ที่เพิ่มประสิทธิภาพการบริหารจัดการที่จะยกเลิกการ async-Ify โดยพื้นฐานแล้วคุณไม่มีเงื่อนงำอีกต่อไปว่านิพจน์ใดจะได้รับการประเมินตามลำดับซึ่งหมายความว่านิพจน์ทั้งหมดจะต้องมีความโปร่งใสในการอ้างอิงซึ่งยากในภาษาเช่น C #

ประเด็นที่สามคือคุณต้องถามว่า "ทำไม async ถึงพิเศษ?" หากคุณจะโต้แย้งว่าการดำเนินการทุกอย่างควรเป็นจริงTask<T>คุณต้องสามารถตอบคำถามได้ว่า "ทำไมไม่Lazy<T>" หรือ "ทำไมไม่Nullable<T>" หรือ "ทำไมไม่IEnumerable<T>" เพราะเราสามารถทำได้อย่างง่ายดาย ทำไมมันไม่ควรจะเป็นกรณีที่การดำเนินงานทุกคนจะยก nullable ? หรือการดำเนินการทุกอย่างเฉื่อยชาคำนวณและผลที่ได้ถูกแคชในภายหลังหรือผลการดำเนินงานทุกคนเป็นลำดับของค่าแทนเพียงค่าเดียว จากนั้นคุณต้องพยายามเพิ่มประสิทธิภาพสถานการณ์เหล่านั้นโดยที่คุณรู้ว่า "โอ้นี่จะต้องไม่เป็นโมฆะฉันจึงจะสร้างโค้ดที่ดีขึ้นได้" และอื่น ๆ

ประเด็นคือ: มันไม่ชัดเจนสำหรับฉันที่Task<T>จริง ๆ แล้วมันพิเศษที่จะรับประกันงานนี้มาก

หากสิ่งเหล่านี้ทำให้คุณสนใจฉันขอแนะนำให้คุณตรวจสอบภาษาที่ใช้งานได้เช่น Haskell ซึ่งมีความโปร่งใสในการอ้างอิงที่ดีกว่ามากและอนุญาตให้มีการประเมินผลนอกลำดับทุกประเภทและทำการแคชอัตโนมัติ Haskell ยังมีการสนับสนุนที่แข็งแกร่งกว่ามากในระบบประเภทของ "การยกเสาเดียว" ที่ฉันพูดถึง


การมีฟังก์ชัน async ที่เรียกโดยไม่ต้องรอไม่สมเหตุสมผลสำหรับฉัน (ในกรณีทั่วไป) หากเราจะลบคุณลักษณะนี้คอมไพเลอร์สามารถตัดสินใจได้เองว่าฟังก์ชันเป็นแบบ async หรือไม่ (เรียกว่า await หรือไม่) จากนั้นเราสามารถมีไวยากรณ์ที่เหมือนกันสำหรับทั้งสองกรณี (async และ sync) และใช้เฉพาะการรอคอยในการโทรเป็นตัวสร้างความแตกต่าง แก้ไขการระบาดของซอมบี้ :)
talkol

ฉันยังคงสนทนาในโปรแกรมเมอร์ตามคำขอของคุณ: programmers.stackexchange.com/questions/209872/…
talkol

@EricLippert - คำตอบที่ดีมากเช่นเคย :) ฉันอยากรู้ว่าคุณสามารถอธิบาย "เวลาแฝงสูง" ได้หรือไม่? ที่นี่มีช่วงทั่วไปเป็นมิลลิวินาทีหรือไม่ ฉันแค่พยายามหาว่าขอบเขตด้านล่างมีไว้สำหรับการใช้ async เพราะฉันไม่ต้องการละเมิด
Travis J

7
@TravisJ: คำแนะนำคือ: อย่าปิดกั้นเธรด UI นานกว่า 30 มิลลิวินาที มากกว่านั้นและคุณจะเสี่ยงต่อการหยุดชั่วคราวที่ผู้ใช้สังเกตเห็นได้
Eric Lippert

1
สิ่งที่ท้าทายฉันคือไม่ว่าบางสิ่งจะทำพร้อมกันหรือไม่พร้อมกันเป็นรายละเอียดการใช้งานที่สามารถเปลี่ยนแปลงได้ แต่การเปลี่ยนแปลงในการใช้งานนั้นบังคับให้เกิดผลกระเพื่อมผ่านรหัสที่เรียกมันรหัสที่เรียกสิ่งนั้นและอื่น ๆ เราจบลงด้วยการเปลี่ยนรหัสเนื่องจากรหัสขึ้นอยู่กับซึ่งเป็นสิ่งที่เราต้องใช้ความพยายามอย่างมากเพื่อหลีกเลี่ยง หรือเราใช้async/awaitเพราะบางสิ่งที่ซ่อนอยู่ใต้ชั้นของสิ่งที่เป็นนามธรรมอาจเป็นแบบอะซิงโครนัส
Scott Hannen

23

เหตุใดฟังก์ชันทั้งหมดจึงไม่ควรเป็นแบบ async

ประสิทธิภาพเป็นเหตุผลหนึ่งดังที่คุณกล่าวมา โปรดทราบว่าตัวเลือก "เส้นทางด่วน" ที่คุณเชื่อมโยงจะช่วยปรับปรุงประสิทธิภาพในกรณีของงานที่เสร็จสมบูรณ์ แต่ยังต้องใช้คำแนะนำและค่าใช้จ่ายที่มากกว่าเมื่อเทียบกับการเรียกวิธีเดียว ด้วยเหตุนี้แม้จะมี "เส้นทางด่วน" อยู่แล้วคุณก็เพิ่มความซับซ้อนและค่าใช้จ่ายจำนวนมากในการเรียกเมธอด async แต่ละครั้ง

ความเข้ากันได้ย้อนหลังรวมถึงความเข้ากันได้กับภาษาอื่น ๆ (รวมถึงสถานการณ์การทำงานร่วมกัน) ก็จะกลายเป็นปัญหาเช่นกัน

อีกเรื่องหนึ่งเป็นเรื่องของความซับซ้อนและเจตนา การดำเนินการแบบอะซิงโครนัสเพิ่มความซับซ้อน - ในหลาย ๆ กรณีคุณลักษณะของภาษาจะซ่อนสิ่งนี้ไว้ แต่มีหลายกรณีที่การสร้างวิธีการasyncเพิ่มความซับซ้อนให้กับการใช้งาน โดยเฉพาะอย่างยิ่งหากคุณไม่มีบริบทการซิงโครไนซ์เนื่องจากวิธีการ async อาจทำให้เกิดปัญหาเธรดที่ไม่คาดคิดได้อย่างง่ายดาย

นอกจากนี้ยังมีกิจวัตรมากมายที่ไม่ได้เป็นแบบอะซิงโครนัสโดยธรรมชาติ สิ่งเหล่านี้มีความหมายมากกว่าการดำเนินการแบบซิงโครนัส ตัวอย่างเช่นการบังคับMath.Sqrtให้เป็นแบบTask<double> Math.SqrtAsyncไร้สาระเนื่องจากไม่มีเหตุผลเลยที่จะเป็นแบบอะซิงโครนัส แทนที่จะมีasyncการผลักดันผ่านการประยุกต์ใช้ของคุณคุณจะจบลงด้วยawaitpropogating ทุกที่

สิ่งนี้จะทำลายกระบวนทัศน์ปัจจุบันโดยสิ้นเชิงรวมทั้งทำให้เกิดปัญหาเกี่ยวกับคุณสมบัติ (ซึ่งเป็นเพียงคู่วิธีที่มีประสิทธิภาพ .. พวกเขาจะไป async ด้วยหรือไม่?) และมีผลกระทบอื่น ๆ ตลอดการออกแบบกรอบงานและภาษา

หากคุณทำงานที่มีขอบเขต IO จำนวนมากคุณมักจะพบว่าการใช้asyncอย่างแพร่หลายเป็นส่วนเสริมที่ดีกิจวัตรหลายอย่างของคุณจะเป็นasyncเช่นนั้น อย่างไรก็ตามเมื่อคุณเริ่มทำงานที่เชื่อมต่อกับ CPU โดยทั่วไปการทำสิ่งต่าง ๆasyncนั้นไม่ดีจริง ๆ นั่นคือการซ่อนความจริงที่ว่าคุณกำลังใช้รอบ CPU ภายใต้ API ที่ดูเหมือนจะเป็นแบบอะซิงโครนัส แต่ก็ไม่จำเป็นต้องเป็นแบบอะซิงโครนัสอย่างแท้จริง


สิ่งที่ฉันกำลังจะเขียน (ประสิทธิภาพ) ความเข้ากันได้แบบย้อนกลับอาจเป็นอีกสิ่งหนึ่ง dll ที่จะใช้กับภาษาเก่าที่ไม่รองรับ async / รอด้วย
Sayse

การสร้าง sqrt async ไม่ใช่เรื่องไร้สาระถ้าเราแค่ลบความแตกต่างระหว่างฟังก์ชั่นซิงค์และ async
talkol

@talkol ฉันเดาว่าฉันจะเปลี่ยนไป - ทำไมการเรียกใช้ฟังก์ชันทุกครั้งจึงต้องใช้ความซับซ้อนของอะซิงโครไนซ์
Reed Copsey

2
@talkol ฉันขอเถียงว่าไม่จำเป็นต้องเป็นความจริง - อะซิงโครไนซ์สามารถเพิ่มข้อบกพร่องที่แย่กว่าการบล็อก ...
Reed Copsey

1
@talkol await FooAsync()ง่ายกว่าFoo()อย่างไร และแทนที่จะเป็นผลโดมิโนขนาดเล็กบางครั้งคุณมีผลกระทบโดมิโนขนาดใหญ่ตลอดเวลาและคุณเรียกสิ่งนั้นว่าการปรับปรุงหรือไม่?
svick

4

นอกเหนือจากประสิทธิภาพ - async อาจมีต้นทุนการผลิต บนไคลเอนต์ (WinForms, WPF, Windows Phone) เป็นประโยชน์สำหรับการผลิต แต่บนเซิร์ฟเวอร์หรือในสถานการณ์อื่น ๆ ที่ไม่ใช่ UI คุณต้องจ่ายผลผลิต แน่นอนคุณไม่ต้องการไป async โดยปริยายที่นั่น ใช้เมื่อคุณต้องการข้อดีในการปรับขนาด

ใช้เมื่ออยู่ที่จุดหวาน ในกรณีอื่นอย่า


2
+1 - ความพยายามอย่างง่าย ๆ ที่จะมีแผนผังความคิดของโค้ดที่ใช้การดำเนินการแบบอะซิงโครนัส 5 รายการควบคู่ไปกับลำดับความสำเร็จแบบสุ่มสำหรับคนส่วนใหญ่จะให้ความเจ็บปวดมากพอสำหรับหนึ่งวัน การให้เหตุผลเกี่ยวกับพฤติกรรมของรหัส async (และด้วยเหตุนี้จึงขนานกันโดยเนื้อแท้) ยากกว่ารหัสซิงโครนัสแบบเก่าที่ดีมาก ...
Alexei Levenkov

2

ฉันเชื่อว่ามีเหตุผลที่ดีที่จะทำให้วิธีการทั้งหมดไม่ตรงกันหากไม่จำเป็นต้องใช้ - ความสามารถในการขยาย วิธีการสร้างแบบคัดสรร async จะใช้งานได้ก็ต่อเมื่อโค้ดของคุณไม่เคยวิวัฒนาการและคุณรู้ว่าเมธอด A () นั้นผูกกับ CPU เสมอ (คุณทำให้มันซิงค์) และวิธี B () จะถูกผูกไว้กับ I / O เสมอ (คุณทำเครื่องหมายว่าเป็น async)

แต่ถ้าสิ่งต่างๆเปลี่ยนไปล่ะ? ใช่ A () กำลังทำการคำนวณ แต่ในอนาคตคุณต้องเพิ่มการบันทึกที่นั่นหรือการรายงานหรือการเรียกกลับที่ผู้ใช้กำหนดด้วยการนำไปใช้งานซึ่งไม่สามารถคาดเดาได้หรืออัลกอริทึมได้ถูกขยายออกไปและตอนนี้ไม่เพียง แต่รวมถึงการคำนวณ CPU เท่านั้น แต่ I / O บางส่วนด้วย? คุณจะต้องแปลงวิธีเป็น async แต่จะทำให้ API เสียหายและผู้โทรทั้งหมดที่อยู่ในสแต็กจะต้องได้รับการอัปเดตเช่นกัน (และอาจเป็นแอปที่แตกต่างกันจากผู้ขายที่แตกต่างกัน) หรือคุณจะต้องเพิ่มเวอร์ชัน async ควบคู่ไปกับเวอร์ชันซิงค์ แต่สิ่งนี้ไม่ได้สร้างความแตกต่างมากนัก - การใช้เวอร์ชันซิงค์จะบล็อกและแทบจะไม่เป็นที่ยอมรับ

จะเป็นการดีมากหากสามารถทำให้วิธีการซิงค์ที่มีอยู่เป็นแบบ async โดยไม่ต้องเปลี่ยน API แต่ในความเป็นจริงเราไม่มีตัวเลือกดังกล่าวฉันเชื่อว่าและการใช้เวอร์ชัน async แม้ว่าจะไม่จำเป็นในตอนนี้ก็เป็นวิธีเดียวที่จะรับประกันได้ว่าคุณจะไม่ประสบปัญหาความเข้ากันได้ในอนาคต


แม้ว่าสิ่งนี้จะดูเหมือนเป็นการแสดงความคิดเห็นที่รุนแรง แต่ก็มีความจริงอยู่มากมาย ประการแรกเนื่องจากปัญหานี้: "สิ่งนี้จะทำลาย API และผู้เรียกทั้งหมดขึ้นสแต็ก" async / await ทำให้แอปพลิเคชันคู่กันแน่นขึ้น มันอาจทำลายหลักการ Liskov Substitution ได้อย่างง่ายดายหากคลาสย่อยต้องการใช้ async / await ตัวอย่างเช่น นอกจากนี้ยังยากที่จะจินตนาการถึงสถาปัตยกรรมไมโครเซอร์วิสที่วิธีการส่วนใหญ่ไม่จำเป็นต้อง async / await
ItsAllABadJoke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.