为长时间的同步操作创建包装器,以使用EAP,APM模式和异步/等待



假设我有一项服务,该服务将进行漫长而昂贵的同步操作,即

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);
    }
}

可以以这种方式完成新的异步/等待运算符的类似事情:

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。

问题:

  • APM的Usplamationmarkservice的实现将如何?
  • 给定EAP和APM版本,如何使用任务类的现有方法(task.factory.startnew/task.factory.fromasync等)包裹它们,以便可以与异步/等等一起使用关键字。

不限制的长期运行同步操作不属于线程池。在The Treadpool中运行此类操作会使您面临饥饿的风险,其中池的旋转线程不足以迅速旋转,无法响应许多其他依赖它的API的需求。

如果您想运行一些漫长的东西,请在自己的线程上运行它,如果需要在某些UI中显示,请小心将结果汇回正确的上下文。

因此,您的第一种方法似乎更合适。

另一方面,TPL提供了暗示任务长期运行的机会,并允许系统决定运行它的最佳位置。就像:

一样简单
Task.Factory.StartNew(someSyncAction, TaskCreationOptions.LongRunning)

StartNew返回任务。您可以等待它。

最新更新