web-dev-qa-db-ja.com

非同期メソッドを作成する方法

C#アプリには単純なメソッドがあり、FTPサーバーからファイルを選択して解析し、データをDBに保存します。ユーザーがAppで他の操作を実行できるように非同期にしたいので、解析が完了したら、「解析が完了しました」というメッセージを取得する必要があります。

非同期メソッド呼び出しで達成できることはわかっていますが、それを行う方法がわかりません誰かが私を助けてくれますか??

別のメソッドを非同期で実行するには、デリゲートとそれらに含まれるBeginInvokeメソッドを使用する必要があります。デリゲートによって実行されているメソッドの終わりに、ユーザーに通知できます。例えば:

class MyClass
{
    private delegate void SomeFunctionDelegate(int param1, bool param2);
    private SomeFunctionDelegate sfd;

    public MyClass()
    {
        sfd = new SomeFunctionDelegate(this.SomeFunction);
    }

    private void SomeFunction(int param1, bool param2)
    {
        // Do stuff

        // Notify user
    }

    public void GetData()
    {
        // Do stuff

        sfd.BeginInvoke(34, true, null, null);
    }
}

http://msdn.Microsoft.com/en-us/library/2e08f6yc.aspx で読む

75
Callum Rogers

この方法を試してください

public static void RunAsynchronously(Action method, Action callback) {
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try {
            method();
        } 
        catch (ThreadAbortException) { /* dont report on this */ } 
        catch (Exception ex) {
        }
        // note: this will not be called if the thread is aborted
        if (callback!= null) callback();
    });
}

使用法:

RunAsynchronously( () => { picks file from FTP server and parses it}, 
       () => { Console.WriteLine("Parsing is done"); } );
19
Zain Ali

非同期で何かをしているときはいつでも、別のスレッド、新しいスレッド、またはスレッドプールから取得したスレッドを使用しています。これは、非同期で行うことはすべて、他のスレッドとの相互作用に非常に注意する必要があることを意味します。

そのための1つの方法は、非同期スレッドのコード(スレッド「A」と呼びます)とそのすべてのデータを別のクラス(クラスを「A」と呼びます)。スレッド「A」がクラス「A」のデータにのみアクセスするようにしてください。スレッド "A"がクラス "A"にのみ接触し、他のスレッドがクラス "A"のデータに接触しない場合、問題は1つ少なくなります。

public class MainClass
{
    private sealed class AsyncClass
    {
        private int _counter;
        private readonly int _maxCount;

        public AsyncClass(int maxCount) { _maxCount = maxCount; }

        public void Run()
        {
            while (_counter++ < _maxCount) { Thread.Sleep(1); }
            CompletionTime = DateTime.Now;
        }

        public DateTime CompletionTime { get; private set; }
    }

    private AsyncClass _asyncInstance;
    public void StartAsync()
    {
        var asyncDoneTime = DateTime.MinValue;
        _asyncInstance = new AsyncClass(10);
        Action asyncAction = _asyncInstance.Run;
        asyncAction.BeginInvoke(
            ar =>
                {
                    asyncAction.EndInvoke(ar);
                    asyncDoneTime = _asyncInstance.CompletionTime;
                }, null);
        Console.WriteLine("Async task ended at {0}", asyncDoneTime);
    }
}

外部から触れられるAsyncClassの唯一の部分はそのパブリックインターフェイスであり、データの唯一の部分はCompletionTimeであることに注意してください。これは、非同期タスクの完了後にonlyタッチされることに注意してください。これは、タスクの内部動作を妨げるものは何もないことを意味し、他のものを妨害することはできません。

6
John Saunders

C#のスレッドに関する2つのリンクを次に示します。

BackgroundWorkerクラス について読み始めます

4
tanascius

Asp.Netでは、実行するジョブに多くのstaticメソッドを使用します。単純に必要な仕事応答なしまたはステータスの場合、以下のような簡単なことを行います。ご覧のように、ResizeImagesまたはResizeImagesAsyncのいずれかを呼び出して、終了するのを待つかどうかを選択できます。

コードの説明: http://imageresizing.net/ を使用して画像のサイズを変更/トリミングし、SaveBlobPngメソッドは画像をAzure(クラウド)に保存しますが、このデモには関係ないので、そのコードは含めませんでした。しかし、時間のかかるタスクの良い例です

private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions);
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
    ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages);
    worker.BeginInvoke(tempuri, versions, deletetemp, null, null);
}
private static void ResizeImages(string tempuri, Dictionary<string, string> versions)
{
    //the job, whatever it might be
    foreach (var item in versions)
    {
        var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value));
        SaveBlobPng(image, item.Key);
        image.Dispose();
    }
}

または、スレッド化することで、デリゲートに煩わされる必要がなくなります。

private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
    Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null));
    t.Start(); 
}
4
Fischer

ThreadPool.QueueUserWorkItem は、異なるスレッドで実行中のプロセスを取得する最も簡単な方法です。

UIオブジェクトには「スレッドアフィニティ」があり、オブジェクトを作成したスレッド以外のスレッドからはアクセスできないことに注意してください。

そのため、ThreadPoolのチェックアウト(またはデリゲートを介した非同期プログラミングモデルの使用)に加えて、 Dispatchers (wpf)または InvokeRequired (winforms)をチェックアウトする必要があります。

1
Will

最後に、何らかのスレッドを使用する必要があります。基本的に機能する方法は、新しいスレッドで関数を開始し、関数の最後まで実行することです。

Windowsフォームを使用している場合、このために用意されている素敵なラッパーはバックグラウンドワーカーと呼ばれます。 UIフォームをロックせずにバックグラウンドで作業でき、フォームと通信して進行状況更新イベントを提供する方法も提供します。

バックグラウンドワーカー

0
QueueHammer

.NETは、asonchrynous関数用の新しいキーワードasyncを取得しました。 docs.Microsoft.com(async) で掘り始めることができます。関数をasonchrynousにする最も一般的な方法は、関数を変更することです[〜#〜] f [〜#〜]

Object F(Object args)
{
    ...
    return RESULT;
}

このようなものに:

async Task<Object> FAsync(Object args)
{
    ...
    await RESULT_FROM_PROMISE;
    ...
    return RESULT;
}

上記のコードで最も重要なことは、コードがawaitキーワードにアプローチすると、FAsync約束された値が返されるまで他の計算を行い、関数内の残りのコードで続行しますFAsync

0
Piotr Wojcik