1

長くて費用のかかる同期操作を行うサービスがあるとします。

class ExclamationMarkService
{
    public string GetData(string param)
    {
        Thread.Sleep(5000);
        return param + "!";
    } 
}

EAPパターンを介して非同期になるようにラップするには、次のようにします。

class ExclamationMarkServiceEAP
{
    public delegate void GetDataHandler(string data);
    public event GetDataHandler GetDataCompleted; 


    public void GetDataWorker(object param)
    {  
            var service = new ExclamationMarkService();
            string data = service.GetData((string)param); 

            if (GetDataCompleted != null)
            {
                GetDataCompleted(data);
            }
    }

    public void GetData(string param)
    {
        var thread = new Thread(GetDataWorker) {IsBackground = true};
        thread.Start(param);
    }
}

新しいasync/await演算子で同様のことが、次のように実行できます。

class ExclamationMarkServiceTaskAsync
{
    public async Task<string> GetDataAsync(string param)
    {
        var service = new ExclamationMarkService();
        return await Task.Run(() => service.GetData(param));
    }
}

使用法:

        public static void CallExclamationMarkServiceEAP()
        {
            var service = new ExclamationMarkServiceEAP();
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetData("hello EAP");
        }

        static void service_GetDataCompleted(string data)
        {
            Console.WriteLine(data);
        }

        public static async void CallExclamationMarkServiceTaskAsync()
        {
            var service = new ExclamationMarkServiceTaskAsync();
            var data = await service.GetDataAsync("hello TaskAsync");
            Console.WriteLine(data);
        }

        static void Main(string[] args)
        {
            CallExclamationMarkServiceEAP();
            CallExclamationMarkServiceTaskAsync();
            Console.Read();
        } 

どちらの場合も、作業をバックグラウンドにオフロードすることができました。EAPの場合、明示的にスレッドを開始します。非同期/待機バージョンの場合は、Task.Runを使用します。

質問:

  • ExclamationMarkServiceのAPM実装はどのようになりますか?
  • EAPとAPMの両方のバージョンがある場合、async / awaitキーワードで使用できるように、Taskクラスの既存のメソッド(Task.Factory.StartNew / Task.Factory.FromAsyncなど)を使用してそれらをラップするにはどうすればよいですか。
4

1 に答える 1

1

IOバウンドではない長時間実行の同期操作は、ThreadPoolに属しません。ThreadPoolでこのような操作を実行すると、飢餓のリスクにさらされます。この場合、プールは、それに依存する他の多くのAPIのニーズに対応するのに十分な速度でスレッドをスピンアップしません。

長時間実行する場合は、独自のスレッドで実行します。UIに表示する必要がある場合は、結果を適切なコンテキストにマーシャリングするように注意してください。

そのため、最初のアプローチの方が適切と思われます。

一方、TPLは、タスクが長時間実行されていることを示唆する機会を提供し、システムがタスクを実行するのに最適な場所を決定できるようにします。それは次のように簡単です:

Task.Factory.StartNew(someSyncAction, TaskCreationOptions.LongRunning)

StartNewタスクを返します。あなたはそれを待つことができます。

于 2012-10-18T14:13:45.103 に答える