async + await == ซิงค์หรือไม่


24

สะดุดกับโพสต์นี้ที่พูดถึงเกี่ยวกับการทำคำขอเว็บ async

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


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

2
แต่ด้วย async คุณสามารถทำ async อื่นได้ในเวลาเดียวกันจากนั้นรอ 2 ด้วยการซิงค์สิ่งนี้เป็นไปไม่ได้
ratchet freak

นี่คือบทความ ( tomasp.net/blog/async-compilation-internals.aspx ) พูดถึงบางส่วนภายใต้กระโปรงของ async ใน C # - เป็นส่วนหนึ่งของชุดที่ครอบคลุมการเขียนโปรแกรมแบบอะซิงโครนัสใน C # และ F #
paul

@ratchetfreak: ใช่นั่นจะไปโดยไม่บอกว่าคุณกำลังโทรหลายสาย
Mrchief

@ R0MANARMY: หากแอปของคุณกำลังทำสิ่งอื่นอยู่ใช่และ async + ที่รอคอยจะเปิดใช้งาน Akim บอกว่าดีที่สุด! แต่ลองจินตนาการว่าโค้ดไม่ได้อยู่ใน button_click handler หรือตัวจัดการเหตุการณ์เช่นนั้นสำหรับเรื่องนั้น หากมีคนคัดลอกรหัส (async + ที่รอสาย) สุ่มสี่สุ่มห้าไปยังวิธีการใด ๆ ก็อาจนำไปสู่การแสดงผลเท็จว่ารหัสของคุณเป็นแบบอะซิงโครนัส แต่อาจไม่มีผล
Mrchief

คำตอบ:


32

ไม่async + await != syncเพราะความต่อเนื่อง

จาก MSDN 'การเขียนโปรแกรมแบบอะซิงโครนัสกับ Async และ Await (C # และ Visual Basic)'

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

ตัวอย่างเช่นการดำเนินการ async จะไม่บล็อกเธรด UI และSome TextBox.Textจะได้รับการอัปเดตหลังจากการดาวน์โหลดเสร็จสิ้น

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}

พูดได้ดีมาก!
Mrchief

คุณช่วยอธิบายรายละเอียดเพิ่มเติมได้ไหม คุณกำลังพูดว่า ... หากไม่มีสิ่งนี้ ... คุณจะไม่สามารถโต้ตอบกับ UI ... ได้เนื่องจากจะเป็นหัวข้อหลัก นี่หมายความว่าสิ่งนี้ใช้ได้เฉพาะในโปรแกรมประเภทแอปพลิเคชันที่ปรากฏบนเว็บโดยที่การโต้ตอบถูกแยกจากเธรดเว็บเซิร์ฟเวอร์ ดังนั้นในเปลือกถั่วนี้กลายเป็นสิ่งสำคัญเท่านั้นเช่นไม่ซิงค์ * เมื่อเธรดหลักของคุณคือเธรดที่กำลังทำงานอยู่ สิ่งนี้จะไม่สร้างพฤติกรรมที่ไม่คาดคิดเช่นในปุ่มสองปุ่มของแอป (1 เธรดหลัก) แต่คุณควรจะคลิกที่ 1 โดยไม่ต้องดำเนินการให้เสร็จก่อน
Seabizkit

เกี่ยวกับConsole.WriteLine(await GetStringOverNetwork());อะไร ถ้าคุณต้องการเอาต์พุตของการเรียกใช้แบบอะซิงโครนัส? โปรแกรมจะบล็อกการเข้าถึงครั้งแรกหรือไม่แม้ว่าเธรดสามารถดำเนินการต่อได้หรือไม่
Andrew

6

ไม่มันไม่เหมือนกัน

asyncบล็อคโค้ดของคุณกำลังรอการawaitโทรกลับเพื่อดำเนินการต่ออย่างไรก็ตามแอปพลิเคชั่นที่เหลือของคุณไม่รอและยังสามารถทำงานต่อได้ตามปกติ

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


ไม่สามารถเรียกใช้การซิงค์เป็น async + กำลังรออยู่
วงล้อประหลาด

@ratchetfreak ฉันคิดว่ามีค่าใช้จ่ายในการตั้งค่าการรอคอย / async อยู่ดังนั้นฉันไม่คิดว่าคุณต้องการรหัสแอปพลิเคชันของคุณทั้งหมด ฉันใช้เพื่อเรียกใช้บล็อกโค้ดที่อาจใช้เวลานานดังนั้นจึงไม่ล็อคแอปพลิเคชันของฉัน :)
Rachel

5

โปรดอนุญาตให้ฉันอธิบายสิ่งต่าง ๆ ที่เกี่ยวข้องกับ async / รอคอย

เมื่อพบการรอคอยเครื่องสถานะพื้นฐานช่วยให้สามารถส่งคืนการควบคุมได้ทันที จากนั้นเมื่อการเรียกที่รอเสร็จสมบูรณ์เครื่องสถานะพื้นฐานจะอนุญาตให้การดำเนินการเพื่อดำเนินการที่บรรทัดหลังจากการโทรที่รอ

ดังนั้นบล็อก async จึงไม่ถูกบล็อกหรือไม่รอสายที่รอให้เสร็จ การควบคุมจะถูกส่งคืนทันทีเมื่อพบคำสั่ง await

เครื่องสถานะพื้นฐานเป็นส่วนหนึ่งของ "เวทย์มนตร์" ที่อยู่เบื้องหลังการใช้ async / รอที่ไม่ได้ใช้งานและพลาด


2

ฉันสะดุดกับคำถามเดียวกันนี้ในใจ แต่หลังจากอ่านคำตอบแล้วคำถามก็ดูเหมือนจะยังคงสับสนโดยอ้างอิงถึง "เวทมนตร์ภายใต้ประทุน"

จากการเขียนโปรแกรม Asynchronousดังกล่าวข้างต้น :

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

บริบทที่พบawaitถูกบล็อกหรือไม่

  • ใช่แล้ว นั่นคือสิ่งกีดขวางการซิงค์ภายในเพื่อรักษาสถานะที่รู้จักในบริบทของการดำเนินการ ยกเว้นบริบทอื่นนั้นหากมีจะไม่เข้าร่วม

ส่วนที่เหลือของแอปพลิเคชันบล็อกawaitหรือไม่

  • ขึ้นอยู่กับการเขียนใบสมัครของคุณ หากเป็นชุดของawaitงานที่ต้องทำตามลำดับที่เปิดตัวตามลำดับในบริบทเดียวกัน (ดู: การพยายามทำความเข้าใจพฤติกรรมการทำงานของ async / await )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    วิธีนี้แต่ละคนawaitจะบล็อกการวางไข่ของคนต่อไป

    ในทางกลับกันงานที่ต้องพึ่งพากันที่เปิดตัวในแบบขนานจะทำงานในแบบคู่ขนานและบริบทจะบล็อกเฉพาะที่การตอบสนองเท่านั้น await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    โดยทั่วไปแล้วการawaitดำเนินการให้ผลตอบแทนกับบริบทด้านนอกจากที่บริบทปัจจุบันเรียกว่า อย่างไรก็ตามถ้าบริบทรอบนอกกำลังรอกระแสอยู่มันก็เหมือนกับลำดับawaitที่อยู่ในบริบทเดียวกัน

ดังนั้นเพื่อที่จะเก็บเกี่ยวasyncผลประโยชน์อย่างใดอย่างหนึ่งความต้องการในการออกแบบการประยุกต์ใช้ในการทำงานบริบทหลายขนาน (UI ข้อมูลลูกค้า ฯลฯ ) แล้วawaitในการดำเนินการที่อัตราผลตอบแทนบริบทแวดล้อมอื่น ๆ awaitเพื่อให้แอพลิเคชันทั้งหมดจะไม่ปิดกั้นในแต่ละ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.