長くて費用のかかる同期操作を行うサービスがあるとします。
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など)を使用してそれらをラップするにはどうすればよいですか。