3

Windowsフォームアプリケーションのバックグラウンドで実行する必要のあるプロセスがいくつかあります。時間がかかりすぎて、完全に終了するまでユーザーインターフェイスをフリーズしたくないため、プロセスを示すインジケーターが必要です。各操作、これまでのところ、各操作の進行状況を表示するフォームがありますが、操作は同期して実行されます。

だから私の質問は、これらの操作(データベースにアクセスする)を非同期で実行する最も簡単な方法は何ですか?

アプリケーションに必要な重要な機能の1つを忘れました。ユーザーは、いつでも操作をキャンセルすることができます。この要件は、少なくとも私の現在のスキルでは、アプリケーションを非常に複雑にしていると思います。基本的に、理解しやすく、実装しやすいソリューションが必要であることを強調したいと思います。従うべき良い習慣があることは承知していますが、この時点で、後でコードを機能させたいと思います。もっと時間をかけてコードをリファクタリングします。

4

3 に答える 3

3

.NET 4 ではTask Parallel Libraryが追加されました。これは、同期操作を非同期にするための非常にクリーンなメカニズムを提供します。

これにより、同期操作をTaskにラップできます。これにより、待機するか、継続 (タスクの完了時に実行されるコード) と共に使用できます。

これは多くの場合、次のようになります。

Task processTask = Task.Factory.StartNew(() => YourProcess(foo, bar));

タスクを取得したら、ブロックを含むかなりの数のオプションがあります。

// Do other work, then:
processTask.Wait(); // This blocks until the task is completed

または、継続が必要な場合 (完了時にコードを実行する):

processTask.ContinueWith( t => ProcessCompletionMethod());

これを使用して、複数の非同期操作を組み合わせたり、それらの一部またはすべてが終了したときに完了することもできます。

Taskこの方法でorを使用するTask<T>と、別の大きな利点があることに注意してください。後で .NET 4.5 に移行した場合、API はコードを変更することなくそのまま動作し、C# 5 で導入される新しい async/await 言語機能を使用できます。

アプリケーションに必要な重要な機能を 1 つ忘れていました。ユーザーはいつでも操作をキャンセルできます。

TPL は、当初から、 .NET 4の新しい協調キャンセル モデルと連携してうまく機能するように設計されています。これによりCancellationTokenSource、タスクの一部またはすべてをキャンセルするために使用できる を使用できます。

于 2012-05-30T23:23:04.487 に答える
2

ORM/データベース API に非同期メソッド自体が付属していない場合は、BackgroundWorker Classを参照してください。キャンセル ( CancelAsync / CancellationPending ) と進行状況レポート ( ReportProgress / ProgressChanged ) の両方をサポートしています。

于 2012-05-30T23:21:01.640 に答える
2

C# では、これを実現する方法がいくつかあります。

個人的には Reactive Extensions を試すことをお勧めします

http://msdn.microsoft.com/en-us/data/gg577609.aspx

実際には次のようなことができます。

https://stackoverflow.com/a/10804404/1268570

私はあなたのためにこれを作成しました。スレッドセーフではありませんが、これは非常に簡単ですが、これは良い出発点になるでしょう

フォームで

var a = Observable.Start(() => Thread.Sleep(8000)).StartAsync(CancellationToken.None);
var b = Observable.Start(() => Thread.Sleep(15000)).StartAsync(CancellationToken.None);
var c = Observable.Start(() => Thread.Sleep(3000)).StartAsync(CancellationToken.None);

Manager.Add("a", a.ObserveOn(this).Subscribe(x => MessageBox.Show("a done")));
Manager.Add("b", b.ObserveOn(this).Subscribe(x => MessageBox.Show("b done")));
Manager.Add("c", c.ObserveOn(this).Subscribe(x => MessageBox.Show("c done")));

private void button1_Click(object sender, EventArgs e)
{
    Manager.Cancel("b");
}

マネージャ ユーティリティ

public static class Manager
{
    private static IDictionary<string, IDisposable> runningOperations;

    static Manager()
    {
        runningOperations = new Dictionary<string, IDisposable>();
    }

    public static void Add(string key, IDisposable runningOperation)
    {
        if (runningOperations.ContainsKey(key))
        {
            throw new ArgumentOutOfRangeException("key");
        }

        runningOperations.Add(key, runningOperation);
    }

    public static void Cancel(string key)
    {
        IDisposable value = null;
        if (runningOperations.TryGetValue(key, out value))
        {
            value.Dispose();
            runningOperations.Remove(key);
        }
    }
于 2012-05-30T23:17:55.937 に答える