Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 任务并行库-任务工厂行为_C#_Multithreading_Asynchronous_Task Parallel Library_Large Files - Fatal编程技术网

C# 任务并行库-任务工厂行为

C# 任务并行库-任务工厂行为,c#,multithreading,asynchronous,task-parallel-library,large-files,C#,Multithreading,Asynchronous,Task Parallel Library,Large Files,我有一个大的(>1GB)文本文件。我需要以多线程方式逐行处理该文件(应用业务逻辑),因此我编写了下一个代码: public Task Parse(Stream content, Action<Trade> parseCallback) { return Task.Factory.StartNew(() => { using (var streamReader = new StreamReader(content)) {

我有一个大的(>1GB)文本文件。我需要以多线程方式逐行处理该文件(应用业务逻辑),因此我编写了下一个代码:

public Task Parse(Stream content, Action<Trade> parseCallback)
{    
   return Task.Factory.StartNew(() =>
   {
      using (var streamReader = new StreamReader(content))
      {
        string line;
        while ((line = streamReader.ReadLine()) != null)
        {
            if (String.IsNullOrWhiteSpace(line))
            {
                continue;
            }

            var tokens = line.Split(TokensSeparator);
            if (!tokens.Any() || tokens.Count() != 6)
            {
                continue;
            }

            Task.Factory.StartNew(() => parseCallback(new Trade
            {
                Id = Int32.Parse(tokens[0]),
                MktPrice = Decimal.Parse(tokens[1], CultureInfo.InvariantCulture),
                Notional = Decimal.Parse(tokens[2], CultureInfo.InvariantCulture),
                Quantity = Int64.Parse(tokens[3]),
                TradeDate = DateTime.Parse(tokens[4], CultureInfo.InvariantCulture),
                TradeType = tokens[5]
            }),
            TaskCreationOptions.AttachedToParent);
        }
      }
   });
}
问题是:

  • 很明显,while循环中的任务创建速度比处理速度快。TPL将如何处理这些排队的任务?他们会等到线程池中的某个线程选择并执行它们,还是有可能丢失它们
  • 调用者线程(parseTask.Wait())是主控制台应用程序线程。在大文件处理期间,我是否能够与console应用程序窗口交互,或者它将被阻止
  • 我意识到提供的方法是错误的。如何改进解决方案?例如:读取文件流并将数据放入主线程中的某个队列,在任务的帮助下处理队列项。还有别的办法吗?请告诉我方向

  • 2+3:如果你启动第二个线程,让它创建任务,UI就不会被阻塞。 不过,您不必这样做——您的主线程可以创建一个任务列表,并等待所有任务(Task.WhenAll)。正如您所说,在循环中创建任务非常快,UI将仅在创建任务所需的时间内被阻止

    编辑:

    我只是意识到你根本不使用异步,这使得我的答案无关紧要。为什么不使用异步从磁盘读取?您可以异步地从磁盘读取大量数据(这是程序中必须耗时的部分,不是吗?),并在数据到达时进行处理

    编辑2:

    这听起来像是一个经典的生产者-消费者场景(我希望我是对的)。请查看以下示例:您有一个线程(主线程,虽然不一定是)异步读取文件中的行,并将它们推送到队列中。另一个线程,消费者,在用户到达时提取行并处理它们。我没有测试代码,我也不希望它工作得很好,这只是一个开始的例子。希望能有帮助

        class ProducerConsumer
        {
            private BlockingCollection<string> collection;
            ICollection<Thread> consumers;
            string fileName;
            public ProducerConsumer(string fileName)
            {
                this.fileName =  fileName;
                collection = new BlockingCollection<string>();
                consumers = new List<Thread>();
                var consumer = new Thread(() => Consumer());
                consumers.Add(consumer);
                consumer.Start();
            }
            private async Task StartWork()
            {
                using (TextReader reader = File.OpenText(fileName))
                {
                    var line = await reader.ReadLineAsync();  
                    collection.Add(line);
                }
            }
            private void Consumer()
            {
                while (true /* insert your abort condition here*/)
                {
                    try
                    {
                        var line = collection.Take();
                        // Do whatever you need with this line. If proccsing this line takes longer then 
                        // fetching the next line (that is - the queue lenght increasing too fast) - you
                        // can always launch an additional consumer thread.
                    }
                    catch (InvalidOperationException) { }
                }
            }
        }
    
    class ProducerConsumer
    {
    私人封锁收集;
    i收集消费者;
    字符串文件名;
    公共ProducerConsumer(字符串文件名)
    {
    this.fileName=文件名;
    collection=newblockingcollection();
    消费者=新列表();
    var consumer=新线程(()=>consumer());
    消费者。添加(消费者);
    consumer.Start();
    }
    专用异步任务StartWork()
    {
    使用(TextReader=File.OpenText(文件名))
    {
    var line=wait reader.ReadLineAsync();
    集合。添加(行);
    }
    }
    私人用户()
    {
    while(true/*在此处插入中止条件*/)
    {
    尝试
    {
    var line=collection.Take();
    //用这条线做任何你需要的。如果处理这条线需要更长的时间
    //获取下一行(即队列长度增长过快)-您
    //始终可以启动其他使用者线程。
    }
    捕获(无效操作异常){}
    }
    }
    }
    

    您可以启动一个专用线程(而不是主线程)作为生产者。因此,它将读取文件并尽可能快地将项目添加到队列中,您的磁盘也可以。如果这对你的消费者来说太快了-只需再启动一个

    您可以通过应用信号量来控制线程 如果需要,它将运行最多320个线程,然后等待前面的线程完成

     public class Utitlity
        {
            public static SemaphoreSlim semaphore = new SemaphoreSlim(300, 320);
            public static char[] TokensSeparator = "|,".ToCharArray();
            public async Task Parse(Stream content, Action<Trade> parseCallback)
            {
                await Task.Run(async () =>
                {
                    using (var streamReader = new StreamReader(content))
                    {
                        string line;
                        while ((line = streamReader.ReadLine()) != null)
                        {
                            if (String.IsNullOrWhiteSpace(line))
                            {
                                continue;
                            }
    
                            var tokens = line.Split(TokensSeparator);
                            if (!tokens.Any() || tokens.Count() != 6)
                            {
                                continue;
                            }
                            await semaphore.WaitAsync();
                            await Task.Run(() =>
                            {
                                var trade = new Trade
                            {
                                Id = Int32.Parse(tokens[0]),
                                MktPrice = Decimal.Parse(tokens[1], CultureInfo.InvariantCulture),
                                Notional = Decimal.Parse(tokens[2], CultureInfo.InvariantCulture),
                                Quantity = Int64.Parse(tokens[3]),
                                TradeDate = DateTime.Parse(tokens[4], CultureInfo.InvariantCulture),
                                TradeType = tokens[5]
                            };
                                parseCallback(trade);
    
                            });
                            semaphore.Release();
                        }
                    }
                });
            }
        }
    
        public class Trade
        {
            public int Id { get; set; }
            public decimal MktPrice { get; set; }
            public decimal Notional { get; set; }
            public long Quantity { get; set; }
            public DateTime TradeDate { get; set; }
            public string TradeType { get; set; }
    
    
        }
    
    公共类实用性
    {
    公共静态信号量slim信号量=新信号量slim(300320);
    公共静态字符[]令牌分离器=“|,”.tocharray();
    公共异步任务解析(流内容、动作解析回调)
    {
    等待任务。运行(异步()=>
    {
    使用(var streamReader=新streamReader(内容))
    {
    弦线;
    而((line=streamReader.ReadLine())!=null)
    {
    if(String.IsNullOrWhiteSpace(行))
    {
    继续;
    }
    var tokens=行分割(TokensSeparator);
    如果(!tokens.Any()| | tokens.Count()!=6)
    {
    继续;
    }
    wait semaphore.WaitAsync();
    等待任务。运行(()=>
    {
    var贸易=新贸易
    {
    Id=Int32.Parse(令牌[0]),
    MktPrice=Decimal.Parse(标记[1],CultureInfo.InvariantCulture),
    概念=Decimal.Parse(标记[2],CultureInfo.InvariantCulture),
    Quantity=Int64.Parse(标记[3]),
    TradeDate=DateTime.Parse(标记[4],CultureInfo.InvariantCulture),
    TradeType=代币[5]
    };
    商业(贸易);;
    });
    semaphore.Release();
    }
    }
    });
    }
    }
    公营贸易
    {
    公共int Id{get;set;}
    公共十进制MktPrice{get;set;}
    公共十进制实数{get;set;}
    公共长数量{get;set;}
    public DateTime TradeDate{get;set;}
    公共字符串类型{get;set;}
    }
    
    更改
    解析
    ,以便它返回一个惰性的
    IEnumerable
    行。事实上,您可以使用内置的
    文件。EnumerateLines
    来删除大部分代码

    然后,使用PLINQ查询:<
     public class Utitlity
        {
            public static SemaphoreSlim semaphore = new SemaphoreSlim(300, 320);
            public static char[] TokensSeparator = "|,".ToCharArray();
            public async Task Parse(Stream content, Action<Trade> parseCallback)
            {
                await Task.Run(async () =>
                {
                    using (var streamReader = new StreamReader(content))
                    {
                        string line;
                        while ((line = streamReader.ReadLine()) != null)
                        {
                            if (String.IsNullOrWhiteSpace(line))
                            {
                                continue;
                            }
    
                            var tokens = line.Split(TokensSeparator);
                            if (!tokens.Any() || tokens.Count() != 6)
                            {
                                continue;
                            }
                            await semaphore.WaitAsync();
                            await Task.Run(() =>
                            {
                                var trade = new Trade
                            {
                                Id = Int32.Parse(tokens[0]),
                                MktPrice = Decimal.Parse(tokens[1], CultureInfo.InvariantCulture),
                                Notional = Decimal.Parse(tokens[2], CultureInfo.InvariantCulture),
                                Quantity = Int64.Parse(tokens[3]),
                                TradeDate = DateTime.Parse(tokens[4], CultureInfo.InvariantCulture),
                                TradeType = tokens[5]
                            };
                                parseCallback(trade);
    
                            });
                            semaphore.Release();
                        }
                    }
                });
            }
        }
    
        public class Trade
        {
            public int Id { get; set; }
            public decimal MktPrice { get; set; }
            public decimal Notional { get; set; }
            public long Quantity { get; set; }
            public DateTime TradeDate { get; set; }
            public string TradeType { get; set; }
    
    
        }
    
    File.EnumerateLines(path)
    .AsParallel()
    .Where(x => !String.IsNullOrWhiteSpace(line))
    .Select(line => ProcessLine(line);