TPL วิธีดำเนินการ 'โทรกลับ'

ฉันมีแอปพลิเคชันขนาดเล็กที่ต้องทดสอบสตริงการเชื่อมต่อ SQL สำหรับการเชื่อมต่อจำนวนหนึ่ง (ทำทีละครั้ง) ในการดำเนินการนี้ ฉันตั้งค่า ConnectionTimeout = 5 ชั่วคราวเพื่อหลีกเลี่ยงการรอนานหากการเชื่อมต่อไม่ถูกต้อง และ ConnectionTimeout = 0 (รอตลอดไป) พูด

เพื่อหลีกเลี่ยงไม่ให้ UI หยุดทำงานในขณะที่เราพยายาม Open() การเชื่อมต่อที่ไม่ดี (แม้ว่า ConnectionTimeout = 5 จะต้องรอ SqlException นานถึงยี่สิบวินาทีก็ตาม) ฉันต้องการรันการทดสอบบนเธรดแยกต่างหากโดยใช้ Task Parallel Library (TPL) ดังนั้นฉันจึงแยกกระทู้ใหม่ของฉันดังนี้:

Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
    (() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;

ปัญหาคือมันยังคงล็อค UI (ชัดเจน) เนื่องจากกำลังรอผลลัพธ์ก่อนที่จะกลับไปหาผู้โทร ฉันจะอนุญาตให้โค้ดคืนการควบคุมไปยัง UI (เพิ่ม GUI) ในขณะที่รับผลลัพธ์ในที่สุดจากอะซิงโครนัส Task ได้อย่างไร

นอกจากนี้ จากภายใน Task ฉันสามารถดำเนินการ MessageBox.Show("Some message") ได้อย่างถูกต้องตามกฎหมายหรือไม่ สิ่งนี้ใช้ไม่ได้กับ BackgroundWorkers และเธรดที่รวมกลุ่มนี้เป็นเธรดพื้นหลังตามค่าเริ่มต้น แต่ดูเหมือนว่าจะไม่เป็นปัญหา ขอบคุณที่สละเวลา.


person MoonKnight    schedule 08.03.2012    source แหล่งที่มา


คำตอบ (2)


คุณพูดถูก นี่คือจุดที่การรอคอยเกิดขึ้น:

 return asyncTestConn.Result;

คุณสามารถสร้างโค้ดเสร็จสิ้นในส่วนท้ายของ TestConnection() หรือใช้ Continuation:

// untested
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
    () => TestConnection(conn, bShowErrMsg));
asyncTestConn.ContinueWith(MyFinishCode);
asyncTestConn.Start()

ฉันสามารถทำ MessageBox.Show("Some message") ได้อย่างถูกต้องตามกฎหมายหรือไม่?

ที่จริงแล้วใช่แล้ว MessageBox นั้นปลอดภัยต่อเธรด น่าจะเป็นไปได้จาก Bgw เช่นกัน

แต่คุณกำลังยืดอายุของ Task ออกไปมาก นั่นไม่ใช่ความคิดที่ดี

person Henk Holterman    schedule 08.03.2012
comment
ขอบคุณมากสำหรับการตอบกลับของคุณ แนวคิดทั้งหมดคือการกลับไปส่งการควบคุมกลับไปยัง UI/GUI โดยเร็วที่สุด สิ่งที่กล่าวมาข้างต้นจะบรรลุผลสำเร็จได้อย่างไร หากฉันกำลังเรียกโค้ดข้างต้นจากวิธีการที่เรียกว่า ParrTestConn(SqlConnection conn, string bShowErrMsg) ฉันก็ไม่สามารถพูดได้ว่า asyncTestConn.ContinueWith(ParrTestConn(conn, bShowErrMsg))... หรือทำได้ไหม? - person MoonKnight; 08.03.2012
comment
@Killer คุณสามารถกลับมาได้หลังจาก Start() GUI ควรตอบสนองเมื่อใช้งานสิ่งนี้ - person Henk Holterman; 08.03.2012
comment
ฉันไม่มีวิธี Task.Factory.Create<T> ใช้ได้ใช่ไหม - person MoonKnight; 08.03.2012

สำหรับ TPL นั้น ContinueWith คือสิ่งที่คุณต้องการอย่างแน่นอน ขยายคำตอบของเฮงก์:

var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg));
// Henk's "MyFinishCode" takes a parameter representing the completed
// or faulted connection-testing task.
// Anything that depended on your "return asyncTestConn.Result;" statement
// needs to move into the callback method.
asyncTestConn.ContinueWith(task =>
    {
        switch (task.Status)
        {
            // Handle any exceptions to prevent UnobservedTaskException.
            case TaskStatus.Faulted: /* Error-handling logic */ break;
            case TaskStatus.RanToCompletion: /* Use task.Result here */ break;
        }
    },
    // Using this TaskScheduler schedules the callback to run on the UI thread.
    TaskScheduler.FromCurrentSynchronizationContext());
person anton.burger    schedule 08.03.2012
comment
มีประโยชน์จริงๆ ขอบคุณ. การรวมกันของทั้งสองคำตอบนั้นมีประโยชน์อย่างยิ่ง - person MoonKnight; 08.03.2012