คุณถามคำถามหลายข้อในคำถามของคุณ ฉันจะทำลายมันให้แตกต่างจากที่คุณทำเล็กน้อย แต่ก่อนอื่นให้ฉันตอบคำถามโดยตรง
เราทุกคนต้องการกล้องที่มีน้ำหนักเบาคุณภาพสูงและราคาถูก แต่เหมือนคำพูดที่ว่าคุณจะทำได้แค่สองในสามส่วนนั้นเท่านั้น คุณอยู่ในสถานการณ์เดียวกันที่นี่ คุณต้องการโซลูชันที่มีประสิทธิภาพปลอดภัยและใช้รหัสร่วมกันระหว่างเส้นทางแบบซิงโครนัสและแบบอะซิงโครนัส คุณจะได้แค่สองอันเท่านั้น
ขอผมแยกเหตุผลว่าทำไม เราจะเริ่มด้วยคำถามนี้:
ฉันเห็นว่ามีคนบอกว่าคุณสามารถใช้GetAwaiter().GetResult()
กับวิธีการซิงค์และเรียกใช้จากวิธีการซิงค์ของคุณหรือไม่ เธรดนั้นปลอดภัยในทุกสถานการณ์หรือไม่
ประเด็นของคำถามนี้คือ "ฉันสามารถแชร์เส้นทางแบบซิงโครนัสและแบบอะซิงโครนัสได้หรือไม่โดยการทำให้เส้นทางแบบซิงโครนัสทำได้โดยง่ายเพียงแค่รอแบบซิงโครนัสกับเวอร์ชันอะซิงโครนัส
ให้ฉันชัดเจนสุดในจุดนี้เพราะมันเป็นสิ่งสำคัญ:
คุณควรหยุดทันทีโดยใช้คำแนะนำจากคนเหล่านั้น
นั่นเป็นคำแนะนำที่แย่มาก มันเป็นสิ่งที่อันตรายมากที่จะดึงข้อมูลพร้อมผลจากงานที่ไม่ตรงกันถ้าคุณมีหลักฐานว่างานได้เสร็จสิ้นการได้ตามปกติหรือผิดปกติ
เหตุผลนี้เป็นคำแนะนำที่ไม่ดีอย่างยิ่งคือให้พิจารณาสถานการณ์นี้ คุณต้องการที่จะตัดหญ้าสนามหญ้า แต่ใบมีดเครื่องตัดหญ้าของคุณเสีย คุณตัดสินใจที่จะติดตามเวิร์กโฟลว์นี้:
- สั่งเบลดใหม่จากเว็บไซต์ นี่คือการดำเนินการแบบอะซิงโครนัสเวลาแฝงสูง
- พร้อมรอ - นั่นคือการนอนหลับจนกว่าคุณจะมีใบมีดในมือ
- ตรวจสอบกล่องจดหมายเป็นระยะเพื่อดูว่าใบมีดมาถึงหรือไม่
- นำใบมีดออกจากกล่อง ตอนนี้คุณมีมันอยู่ในมือ
- ติดตั้งใบมีดในเครื่องตัดหญ้า
- ต้ดหญ้า.
เกิดอะไรขึ้น? คุณนอนหลับตลอดไปเพราะการดำเนินงานของการตรวจสอบจดหมายอยู่ในขณะนี้รั้วรอบขอบชิดในสิ่งที่เกิดขึ้นหลังจากจดหมายมาถึง
เป็นเรื่องง่ายมากที่จะเข้าสู่สถานการณ์นี้เมื่อคุณรองานโดยพลการ งานนั้นอาจมีการกำหนดเวลาทำงานในอนาคตของเธรดที่กำลังรออยู่และตอนนี้อนาคตนั้นจะไม่มาถึงเพราะคุณกำลังรองานอยู่
หากคุณรอแบบอะซิงโครนัสทุกอย่างก็โอเค! คุณตรวจสอบจดหมายเป็นระยะและในขณะที่คุณกำลังรอคุณทำแซนด์วิชหรือทำภาษีหรืออะไรก็ตาม คุณทำงานต่อไปเรื่อย ๆ ขณะที่รอ
อย่ารอพร้อมกัน ถ้างานจะทำก็คือไม่จำเป็น หากงานไม่เสร็จ แต่กำหนดให้รันเธรดปัจจุบันจะไม่มีประสิทธิภาพเนื่องจากเธรดปัจจุบันอาจให้บริการงานอื่นแทนการรอ หากงานไม่เสร็จและกำหนดเวลาให้รันเธรดปัจจุบันงานจะค้างเพื่อรอพร้อมกัน ไม่มีเหตุผลที่ดีที่พร้อมรออีกครั้งจนกว่าคุณจะรู้อยู่แล้วว่างานจะเสร็จสมบูรณ์
สำหรับการอ่านเพิ่มเติมในหัวข้อนี้ดู
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
สตีเฟ่นอธิบายสถานการณ์โลกแห่งความเป็นจริงได้ดีกว่าที่ฉันสามารถทำได้
ตอนนี้ลองพิจารณา "ทิศทางอื่น" เราสามารถแชร์รหัสโดยการทำให้รุ่นอะซิงโครนัสสามารถทำเวอร์ชันซิงโครนัสกับเธรดผู้ปฏิบัติงานได้หรือไม่?
นั่นคืออาจจะเป็นและแน่นอนอาจจะเป็นความคิดที่ไม่ดีด้วยเหตุผลดังต่อไปนี้
จะไม่มีประสิทธิภาพหากการดำเนินการซิงโครนัสเป็น IO latency สูง สิ่งนี้จ้างคนงานเป็นหลักและทำให้คนงานนั้นหลับจนกว่างานจะเสร็จ หัวข้อที่มีราคาแพงเมามัน พวกเขาใช้พื้นที่ที่อยู่ขั้นต่ำเป็นล้านไบต์โดยค่าเริ่มต้นใช้เวลาพวกเขาใช้ทรัพยากรระบบปฏิบัติการ คุณไม่ต้องการที่จะเผาไหม้ด้ายทำงานไร้ประโยชน์
การดำเนินการแบบซิงโครนัสอาจไม่สามารถเขียนเป็นเธรดที่ปลอดภัยได้
นี่เป็นเทคนิคที่เหมาะสมกว่าหากงานที่มีความหน่วงสูงมีการเชื่อมโยงกับโปรเซสเซอร์ แต่ถ้าเป็นเช่นนั้นคุณอาจไม่ต้องการส่งมันไปยังเธรดผู้ปฏิบัติงาน คุณอาจต้องการที่จะใช้งานห้องสมุดขนานไปคู่ขนานมันเป็นซีพียูมากที่สุดเท่าที่เป็นไปได้คุณอาจต้องการตรรกะการยกเลิกและคุณไม่สามารถเพียงแค่ทำให้รุ่นซิงโครทำได้ทุกที่เพราะแล้วมันจะเป็นรุ่นที่ไม่ตรงกันอยู่แล้ว
อ่านเพิ่มเติม; อีกครั้งสตีเฟนอธิบายอย่างชัดเจนมาก:
ทำไมไม่ใช้ Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html
สถานการณ์เพิ่มเติม "ทำและไม่ทำ" สำหรับ Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html
ถ้าเช่นนั้นเราจะทิ้งอะไรไว้กับ เทคนิคทั้งสองสำหรับการแบ่งปันรหัสนำไปสู่การหยุดชะงักหรือไร้ประสิทธิภาพขนาดใหญ่ ข้อสรุปที่เราไปถึงคือคุณต้องเลือก คุณต้องการโปรแกรมที่มีประสิทธิภาพและถูกต้องและทำให้ผู้โทรพอใจหรือคุณต้องการบันทึกการกดแป้นบางครั้งโดยการทำซ้ำรหัสจำนวนเล็กน้อยระหว่างเส้นทางซิงโครนัสและอะซิงโครนัสหรือไม่? คุณไม่ได้ทั้งสองอย่างฉันกลัว