TPL Cara Melakukan 'Panggilan Kembali'

Saya memiliki aplikasi kecil yang perlu menguji string koneksi SQL untuk sejumlah koneksi (masing-masing dilakukan satu per satu). Untuk melakukan ini saya mengatur ConnectionTimeout = 5 sementara untuk menghindari menunggu lama jika koneksi tidak valid dan ConnectionTimeout = 0 (tunggu selamanya), katakanlah.

Untuk menghindari UI hang saat kami mencoba Open() koneksi yang buruk (bahkan dengan ConnectionTimeout = 5 waktu menunggu SqlException bisa mencapai dua puluh detik), saya ingin menjalankan pengujian pada thread terpisah menggunakan Task Parallel Library (TPL). Jadi saya spin-off thread baru saya seperti:

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

Masalahnya adalah ini masih mengunci UI (jelas), karena menunggu hasilnya sebelum kembali ke pemanggil. Bagaimana cara mengizinkan kode untuk mengembalikan kontrol ke UI (membebaskan GUI) sambil mendapatkan hasil akhir dari Task asinkron?

Selain itu, dari dalam Task dapatkah saya melakukan MessageBox.Show("Some message") secara sah? Ini tidak berfungsi untuk BackgroundWorkers dan thread gabungan ini adalah thread latar belakang secara default; namun sepertinya hal itu tidak menjadi masalah. Terima kasih atas waktunya.


person MoonKnight    schedule 08.03.2012    source sumber


Jawaban (2)


Anda benar, di sinilah penantian terjadi:

 return asyncTestConn.Result;

Anda cukup membuat kode penyelesaian di bagian belakang TestConnection() atau menggunakan Lanjutan:

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

bisakah saya melakukan MessageBox.Show("Some message") secara sah?

Sebenarnya Ya, MessageBox aman untuk thread. Seharusnya bisa dari Bgw juga.

Tapi Anda memperpanjang umur Tugas, itu bukan ide yang bagus.

person Henk Holterman    schedule 08.03.2012
comment
Terima kasih banyak atas tanggapan Anda. Ide keseluruhannya adalah untuk kembali memberikan kendali kembali ke UI/GUI sesegera mungkin, bagaimana hal di atas dapat mencapainya? Jika saya memanggil kode di atas dari metode yang disebut ParrTestConn(SqlConnection conn, string bShowErrMsg) maka saya tidak bisa mengatakan asyncTestConn.ContinueWith(ParrTestConn(conn, bShowErrMsg))... Atau bisakah? - person MoonKnight; 08.03.2012
comment
@Killer Anda cukup kembali setelah Start(). GUI harus tetap responsif saat menggunakan ini. - person Henk Holterman; 08.03.2012
comment
Saya tidak memiliki metode Task.Factory.Create<T> yang tersedia? - person MoonKnight; 08.03.2012

Untuk TPL, ContinueWith adalah yang Anda inginkan. Memperluas jawaban Henk:

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
Sangat membantu. Terima kasih. Kombinasi kedua jawaban ini benar-benar bagus. - person MoonKnight; 08.03.2012