首页 > 解决方案 > C#:后台任务中的耗时操作入队?

问题描述

我正在与一些后台进程作斗争。我的控制台应用程序中有两种方法。Aprivate static async Task<Dictionary<string, string>> GenerateSomething()和另一种方法将某些内容发送到网络服务器。GenerateSomething-Method 比 Method 花费更多的时间private static async SendSomething()。现在我有了在后台多次运行 GenerateSomething() 方法并用返回填充每个任务的队列的想法。

我已经开始编程,但我不知道如何在后台运行多个 GenerateSomething() 方法,而 SendSomething() 正在处理它自己。

这是我的最新结果:

    class Program
    {
        private static Queue<Dictionary<string, string>> QueueOfDicts = new Queue<Dictionary<string, string>>();
        private static int batchCount = 5000;
        private static int queueMinThreshold = 10;
        private static long genCounter = 0;
        private static long dictCounter = 0;
        private static Stopwatch stopwatch = new Stopwatch();
        static void Main(string[] args)
        {
            GetSomething().Wait();
        }
        private static async Task<Dictionary<string, string>> GenerateSomething()
        {
            var Dict = new Dictionary<string, string>();

           // Here I do some calculations which takes approximately 30 seconds
            for (int i = 0; i < batchCount; i++)
            {
            // some calculations
            }
            dictCounter++;
            Console.WriteLine($"Added Dict #{dictCounter} with {batchCount} to the Queue.");
            return Dict;
        }
        private static async Task SendSomething()
        {
            long time = 0;
            long avgTime = 0;
            var counter = 0;
        while (true)
        {
            try
            {
                var url = "https://.............";
                var web = new Web(url);
                var address = "xxxxxxxxxxx";
                var service = new Service(web, address);

                if (QueueOfDicts.Count > queueMinThreshold)
                {
                    var result = QueueOfDicts.Dequeue();
                    Console.WriteLine("QueueCount: " + QueueOfDicts.Count);
                    try
                    {
                        stopwatch.Start();
                        // here i wait send the webresponse, which takes about 5 seconds
                        stopwatch.Stop();
                        time = stopwatch.ElapsedMilliseconds;
                        stopwatch.Reset();
                    }
                    catch (Exception ex)
                    {
                        await SendFailedMessage(ex);
                        GetSomething().Wait();
                    }

                    var index = 0;
                    foreach (var res in result)
                    {
                        //do something
                        index++;
                    }
                    genCounter += batchCount;
                    avgTime += time;
                    counter++;
                    if (counter >= 100000 / batchCount)
                    {
                        Console.WriteLine("Average " + avgTime / counter);
                        counter = 0;
                        avgTime = 0;
                    }
                    Console.WriteLine("{0} analyzes made -- LastCall: {1}ms", genCounter, time);
                }
                else
                    QueueOfDicts.Enqueue(await GenerateSomething());
            }

            catch (Exception ex)
            {
                Console.WriteLine("-----------ERROR----------: \n End with error: \n" + ex.ToString());
                await SendFailedMessage(ex);
                Console.WriteLine("Querytime:" + time);
                Console.ReadLine();
            }
        }
    }
    private static async Task<Message> SendFailedMessage(Exception ex)
    {
        var Bot = new TelegramBotClient(".....");
        return await Bot.SendTextMessageAsync("...", "Something went wrong: \n" + ex);
    }
}

谁能帮助我,我如何private static async Task<Dictionary<string, string>> GenerateSomething()在后台多次运行,同时private static async SendSomething()做自己的工作?

希望你有足够的信息来帮助我。感谢所有可以帮助我完成这个小项目的人。

标签: c#backgroundqueuetask

解决方案


为简单起见,我删除了与您的内部类有关的大部分代码。

目前在后台并行执行多个任务的最简单方法是使用 async-await 模式,即使用Tasks. 下面你有一个这样的事情的最小例子,没有进入额外的细节,比如锁、线程安全等。

我建议对 C# 的任务并行库感兴趣,它会对你有很大帮助。

using System;
using System.Threading.Tasks;
using System.Collections.Generic;

class Program
{
    private static int batchCount = 5000;
    private static int queueMinThreshold = 10;
    static async Task Main(string[] args)
    {
        // Run 10 times
        var arr = new Task<Dictionary<string, string>>[queueMinThreshold];
        for (int i = 0; i < queueMinThreshold; i++)
        {
            int id = i;
            arr[i] = Task.Run(async () => await GenerateSomething(id));
        }

        // Do whatever in the meantime
        // Execute some other function call, like SendSomething()
        // ...


        // Finally await result of long-running operations (When all of them are finished)
        await Task.WhenAll(arr);

        // And, if needed, access those reults
        var firstResult = arr[0].Result; // non-blocking call - it is already finished.
    }

    private static async Task<Dictionary<string, string>> GenerateSomething(int id)
    {
        var Dict = new Dictionary<string, string>();
        // Here I do some calculations which takes approximately 30 seconds
        for (int i = 0; i < batchCount; i++)
        {
        // some calculations
        }

        Console.WriteLine($"Added Dict #{id} with {batchCount} to the Queue.");
        return Dict;
    }
}

推荐阅读