0

Отредактирую свой вопрос, так как из стадии алгоритма я перешёл в режим написания кода.

Программа недоделанная, я не спорю.
Интересует вот что. Как производить правильно парсинг файлов и записывать мою статистику по всем файлам.
Примерное содержимое текстовых файлов такое.

user    adres     trafik  data   User1   Yandex    110     26.06 
User2   Yandex    600     23.07  User3   Google    700     12.08 
User1   Yahoo     800     28.08  User3   Google    100     13.09 
User2   Yandex    120     14.09  User1   Google    140     27.09 
User3   Yahoo     100     23.10  User2   Google    150     16.11 
User1   Yandex    160     17.11  User3   Yahoo     110     24.11 
User2   Google    700     25.11  User1   Yandex    900     18.12

Процедуру объединения статистик я нашёл и вставил, но нужна подсказка как двигаться дальше.

На лабораторную работу дали такое задание (Язык C#)

Предполагая, что в некотором каталоге на диске сохранено большое количество файлов с логами (журналами работы) прокси-сервера, написать программу вычисляющую статистику потребления трафика сети Интернет. На выходе программа должна создавать три текстовых документа: статистика по пользователям, статистика по доменам, статистика по датам. В качестве статистики использовать общий объем потребленного трафика, соответственно пользователем за все дни, при обращении к домену, в указанный день.
При разработке программы считать, что каждый файл должен обрабатываться отдельно параллельно выполняющимся участком кода. После обработки всех файлов, полученные результаты для каждого из них должны суммироваться в общую сводку.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using System.IO;
using System.Diagnostics.Eventing.Reader;
using System.Threading.Tasks;

namespace Лабораторная_2
{    

    class countFiles
    {      
        ///string archiveDirectory = @"D:\logfiles";
        string[] filelist = Directory.GetFiles(@"D:\logfiles", "*.txt");
        public string user 
        { get; set; }
        public string adres
        { get; set; }
        public string trafik
        { get; set; }
        public string data
        { get; set; }

        void parsingfiles(string line)
        {
            foreach (string file_to_read in filelist)
            {

            }
            string[] parts = line.Split('\t');
            user = parts[0];
            adres = parts[1];
            trafik = parts[2];
            data = parts[3];
        }

        public void ReadFile(string filename)
        {
            using (StreamReader sr = new StreamReader(filename))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    parsingfiles(line);
                }
            }
        }  
}


    class StatLog:countFiles
    {
       public Dictionary<String, UInt64> userstat;
       public Dictionary<String, UInt64> adrestat;
       public Dictionary<int, UInt64> trafikstat;

       public StatLog()//конструктор 
       {
           userstat = new Dictionary<String, UInt64>();
           adrestat = new Dictionary<String, UInt64>();
           trafikstat = new Dictionary<int, UInt64>();
       }

     public StatLog createStat(StatLog info)//
     {
         UInt64 value;
         foreach (var item in info.userstat)
            {              
                userstat[item.Key] = (userstat.TryGetValue(item.Key, out value) ? value : 0) + item.Value;
            }
            foreach (var item in info.adrestat)
            {
                adrestat[item.Key.Trim()] = (adrestat.TryGetValue(item.Key.Trim(), out value) ? value : 0) + item.Value;
            }
            foreach (var item in info.trafikstat)
            {
                trafikstat[item.Key] = (trafikstat.TryGetValue(item.Key, out value) ? value : 0) + item.Value;
            }
            return this;
     }  
    }

    class injectfile : StatLog
    {
        static Queue<String> m_workFiles = new Queue<String>();//очередь файлов с каталога
        static System.Collections.Generic.List<StatLog> m_threadResult;//результат выполнения потока
        static bool m_iscomplete = false;//флаг завершения ввода
        static readonly object m_locker = new object(); //мьютекс для работы с файлами выводимых в очередь

        public void injected(String filelist)//выгрузка файлов в очередь для обработки
        {
            if (!Directory.Exists(filelist))
            {
                return;
            }
            lock (m_locker)
            {
                foreach (var x in Directory.EnumerateFiles(filelist))
                {
                    m_workFiles.Enqueue(x);
                }
            }
            m_iscomplete = true;//установить флаг завершения
        }

        static StatLog processFile(String file)//обработка файла
        {
            if (!File.Exists(file))///Проверка на наличие файла в каталоге
            {
                return new StatLog();
            }
            StreamReader sr = System.IO.File.OpenText(file);
            String line;
            StatLog sc = new StatLog();//
            while ((line = sr.ReadLine()) != null)
            {
                var e = countFiles.parsingfile(line);               
            }
            return sc;
        }


        static public void threadFunc(int id)
        {
            String value;
            StatLog localStat = m_threadResult[id];
                value = m_workFiles.Dequeue();//получение первого файла из очереди с удалением его из очереди
                var fileStat = processFile(value);//обработать файл
                localStat.createStat(fileStat);//объединить статистику
        }       
    }

    class Program
    {
            static void Main(string[] args)
        {

           int threadCount = 7;//задаём количество потоков
           string[] filelist = Directory.GetFiles(@"D:\logfiles", "*.txt");
           System.Threading.Thread[] threads = new System.Threading.Thread[threadCount];          
           injectfile inF=new injectfile();
                inF.injected(filelist);
                 foreach (var t in threads)
                 {
                     inF.createStat();
            }
            //Создаём поток
            StreamWriter sw = new StreamWriter(@"D:\userstat.txt");
            //Пишем в файл
            for (int i = 0; i < .Count; i++)
            {
                ///sw.WriteLine(Txt_Struct[i].user);
            }
            sw.Close();


            StreamWriter sw1 = new StreamWriter(@"C:\adrestat.txt");
            //Пишем в файл
            for (int i = 0; i < .Count; i++)
            {
                //sw1.WriteLine(Txt_Struct[i].adres);

            }
            sw1.Close();

            StreamWriter sw2 = new StreamWriter(@"D:\trafikstat.txt");
            //Пишем в файл
            for (int i = 0; i < .Count; i++)
            {
               /// sw2.WriteLine(Txt_Struct[i].trafik);             
            }
            sw2.Close();
        }
    }
}
Stack
  • 9,452
beginner
  • 380
  • Так и не понял, нужны медоты из .NET или алгоритм? Рекомендую почитать про многопоточное программирование на шарпе для начала – koks_rs Dec 11 '15 at 16:03
  • Алгоритм как мне свои файлы которые я считываю вписать в поток и извлекать из них нужную информацию. А если трудно с описанием то можно и методы .NET – beginner Dec 11 '15 at 16:16

1 Answers1

3

Вы нашли свои файлы. Выводить ничего никуда не надо. Надо распарсить эти файлы и агрегировать данные. Потом можно эти обработанные данные выводить или сохранять или делать, что нравится. Файлы однотипные, если я правильно понял. Значит, можно запустить один код в несколько потоков.

При этом агрегацию данных для каждого файла можно делать внутри потока, а по завершении передавать в основной поток и там уже сложить все в кучу. А можно разобрать строку лога и передать необходимые данные в родительский поток. Разница в том, что в первом случае жрем больше памяти, но не толкаемся локтями на передаче данных между потоками, а во втором все наоборот.

В основном потоке необходимо реализовать некий менеджер. В самом простом варианте он запускает количество потоков по количеству логов, принимает данные пока все треды не отработают. Вариант так себе - треды будут простаивать из-за диска. Вообще, казалось бы такой классический пример распараллеливания как раз на этом и не дает заметного уменьшения времени выполнения задачи. В общем, тут надо смотреть по конкретной задаче и не плодить треды, когда оно не дает прироста производительности.

Второй момент, тормозящий задачу - разбор строки лога. Самое простое и удобное - накатать регулярку и получить все на блюдечке. Но оно не самое эффективное. У меня на похожей задаче регулярками 31 гигабайт парсился 51 минуту, а сплитами и сабстрингами - 8.

Что касается именно многопоточности c#, то тут MSDN вам в руки и примеров море.

Ну и самое главное, раз уж эта задача у вас учебная. Нарисуйте свой многопоточный код, поиграйтесь с ним, а потом расскажите преподу, когда многопоточность не есть хорошо. И с чистой сосестью получите свой автомат.а

  • Добрый день! Спасибо за подсказку вам. Сейчас работаем на этим. И ещё паралельно дали задачу используя такое же задание но уже использовать Task

    Если не трудно тоже можете словесно описать что от меня там требуется.уже с Task.

    Ваш алгоритм помог,сейчас я работаю над ним.

    – beginner Jan 04 '16 at 15:45
  • Увы, на шарпе я не писал уже больше пяти лет. Поэтому не подскажу. Вам лучше создать отдельный вопрос, если что-то непонятно по использованию Task. – Ivan Soshnikov Jan 04 '16 at 19:57