【问题标题】:Long Running Task Not Having Access to Console?长时间运行的任务无法访问控制台?
【发布时间】:2019-01-18 19:24:34
【问题描述】:

我正在写一个生产者->队列->消费者->队列2->消费者2应用程序

我让 consumer2 等待列表达到阈值,然后启动另一个模拟长时间运行任务的任务(例如 SQL Multi=insert)。

但是,当我运行应用程序时,“长时间运行的任务”(LongRunningTaskInsert()) 似乎要等到所有队列都发出完成信号后再写入控制台。

当我调试时,List Lists 变量显示一些任务正在应用程序的中间完成。 我在任务中做错了什么/淘气吗?

代码:

class Program
{
    static  void Main(string[] args)
    {
        BlockingCollection<string> bag1 = new BlockingCollection<string>();
        BlockingCollection<string> bag2 = new BlockingCollection<string>();
        var Tasks = new List<Task>();
        List<string> Container = new List<string>();

        Task consumer2 = Task.Factory.StartNew(() =>
        {
            foreach (var item in bag2.GetConsumingEnumerable())
            {
                Container.Add(item);
                if (bag2.IsCompleted || Container.Count > 5)
                {
                    Console.WriteLine("Container:");
                    Container.ForEach(y =>
                    {
                        Console.Write($"Value: {y}, ");
                    });
                    Console.Write("\n");

                    var newTask = Task.Factory.StartNew(() => {
                        Thread.Sleep(2000);
                        LongRunningTaskInsert();

                    }
                    );
                    Tasks.Add(newTask);

                    Container.Clear();
                }
            }

            Task.WhenAll(Tasks);
        });

        //this is a task that evaluates all available elements on separate threads.
        Task consumer1 = Task.Factory.StartNew(() =>
        {
            //do something with the consumer
            Parallel.ForEach(
                bag1.GetConsumingEnumerable(),
                (x) =>
                {
                    Console.WriteLine($"Consumer {x} => bag2, thread {Thread.CurrentThread.ManagedThreadId}");
                    bag2.Add(x);
                });
            bag2.CompleteAdding();

        });

        Task producer = Task.Factory.StartNew(() =>
        {
            //do something to put records into the bad
            for (int i = 0; i < 10; i++)
            {


                System.Threading.Thread.Sleep(500);

                bag1.Add(i.ToString());
                bag1.Add((i * 10).ToString());
                bag1.Add((i + 10).ToString());
                Console.WriteLine($"Producer: {i} & { i * 10} & {i + 10}");
            }

            bag1.CompleteAdding();
        });

        producer.Wait();
        consumer1.Wait();
        consumer2.Wait();
        Console.Read();
    }

    private static bool LongRunningTaskInsert()
    {
        //Thread.Sleep(1000);
        Console.WriteLine("Long Running Task Complete");
        return true;
    }
}

编辑: 我得到的输出是:

制作人:0 & 0 & 10
消费者 0 => bag2,线程 4
消费者 0 => bag2,线程 6
消费者 10 => bag2,线程 5
制作人:1 & 10 & 11
消费者 10 => bag2,线程 8
消费者 11 => bag2,线程 10
消费者 1 => bag2,线程 9
容器:
值:0,值:0,值:10,值:10,值:11,值:1,
制片人:2 & 20 & 12
消费者 20 => bag2,线程 4
消费者 2 => bag2,线程 6
消费者 12 => bag2,线程 5
制片人:3 & 30 & 13
消费者 3 => bag2,线程 10
消费者 30 => bag2,线程 9
消费者 13 => bag2,线程 8
容器:
值:20,值:2,值:12,值:3,值:30,值:13,
制作人:4 & 40 & 14
消费者 4 => bag2,线程 4
消费者 40 => bag2,线程 6
消费者 14 => bag2,线程 5
制片人:5 & 50 & 15
消费者 5 => bag2,线程 10
消费者 15 => bag2,线程 8
消费者 50 => bag2,线程 9
容器:
值:4,值:40,值:14,值:5,值:15,值:50,
制片人:6 & 60 & 16
消费者 6 => bag2,线程 6
消费者 60 => bag2,线程 6
制片人:7 & 70 & 17
消费者 16 => bag2,线程 4
消费者 70 => bag2,线程 5
消费者 17 => bag2,线程 5
消费者 7 => bag2,线程 4
容器:
值:6,值:60,值:16,值:70,值:17,值:7,
制片人:8 & 80 & 18
消费者 8 => bag2,线程 6
消费者 80 => bag2,线程 6
制片人:9 & 90 & 19
消费者 90 => bag2,线程 4
消费者 19 => bag2,线程 4
消费者 18 => bag2,线程 8
消费者 9 => bag2,线程 8
容器:
值:8,值:80,值:90,值:19,值:18,值:9,
长时间运行的任务完成
长时间运行的任务完成
长时间运行的任务完成
长时间运行的任务完成
长时间运行的任务完成

我希望将“长时间运行的任务完成”混在一起,而不是最后全部聚集在一起。

【问题讨论】:

  • 如果您将SetMinThreads (docs.microsoft.com/en-us/dotnet/api/…) 预先设置为 50,行为是否会改变?
  • @mjwills 当我将最小工作线程设置为 50 并将完成端口线程设置为 8 时没有变化
  • 如果我将生产者任务移动到外部方法并将其标记为异步并更改 Thread.Sleep -> await Task.Delay() 我开始得到不同的结果,并且我在控制台调用中混入了长期运行的任务..
  • 看起来 Parallel.Foreach 语句正在产生一堆线程,而我的方法 LongRunningTaskInsert() 没有得到任何时钟时间。如果我将其更改为同步 foreach 循环,我的线程数从 8 个减少到 4 个,我得到了我期望的结果(混合了长时间运行的任务控制台调用)。

标签: c# concurrency task


【解决方案1】:

Parallel.Foreach 语句产生了一堆线程,而我的方法 LongRunningTaskInsert() 没有得到任何时钟时间。如果我将其更改为同步 foreach 循环,我的线程数将从 8 减少到 4 并且我得到我期望的结果(混合了长时间运行的任务控制台调用)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 2014-10-26
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多