简体   繁体   English

为长时间的同步操作创建包装器,以使用eap,apm模式和async / await

[英]creating a wrapper for a long synchronous operation to use eap, apm pattern and async/await

Suppose I have a service which will be doing a long, expensive synchronous operation, ie 假设我有一项服务将执行长时间的,昂贵的同步操作,即

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

To wrap it to become asynchronous via the EAP pattern I can do this: 要将其包装为通过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);
    }
}

A similar thing with the new async/await operators can be done this way: 使用新的async / await运算符可以执行以下类似操作:

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

Usage: 用法:

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

In both cases I managed to offload the work to the background. 在这两种情况下,我都设法将工作转移到后台。 In the case of EAP, by explicitly starting a thread. 在EAP的情况下,通过显式启动线程。 For the async/await version, by using Task.Run. 对于异步/等待版本,请使用Task.Run。

Questions: 问题:

  • How would an APM implementation of my ExclamationMarkService look like? 我的ExclamationMarkService的APM实现如何?
  • Given both EAP and APM versions, how can they be wrapped by using existing methods of the Task class (Task.Factory.StartNew / Task.Factory.FromAsync, etc.) so that they could be used with the async/await keywords. 给定EAP和APM版本,如何使用Task类的现有方法(Task.Factory.StartNew / Task.Factory.FromAsync等)将它们包装起来,以便可以与async / await关键字一起使用。

Long running synchronous operations that are not IO bound do not belong in the ThreadPool. 没有IO绑定的长时间运行的同步操作不属于ThreadPool。 Running such operations in the ThreadPool exposes you to the risk of starvation, where the pool does not spin up threads fast enough to be responsive to the needs of the many other APIs that rely on it. 在ThreadPool中运行此类操作会使您面临饥饿的风险,在这种情况下,池无法以足够快的速度启动线程以响应依赖它的许多其他API的需求。

If you want to run something long-winded, run it on your own thread, being careful to marshall the result back to the right context if it needs to show in some UI. 如果要长时间运行某些内容,请在自己的线程上运行,如果需要在某些UI中显示,请小心将结果编组回正确的上下文。

As such your first approach seems more appropriate. 因此,您的第一种方法似乎更合适。

On the other hand, TPL offers the opportunity to hint that the task is long running, and allows the system to decide the best place to run it. 另一方面,TPL提供了暗示任务长期运行的机会,并允许系统确定运行任务的最佳位置。 It's as simple as: 就像这样简单:

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

StartNew returns a Task. StartNew返回一个任务。 You can await it. 您可以等待。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM