использовать GPU / TPL на C # коде, чтобы ускорить процесс, занимая 40 минут - PullRequest
0 голосов
/ 09 июня 2019

Я хочу выполнить некоторые вычисления для текстового файла, который имеет 1 число "0,1" в каждой строке и имеет почти 1 миллион строк.

То, что я хочу проверить, сколько раз существует последовательность во всем файле, и она делает последовательность в соответствии с sequence length, например, мой файл:

01100101011 .... до1 миллион (каждое число в новой строке)

код

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

public class Program
{
    static void Main(string[] args)
    {
        Stopwatch time = new Stopwatch();
        time.Start();
        try
        {
            // I have hard coded fileName and Sequence Length that i am taking from user
            string data = "", fileName = "10.txt";  // this file has almost 1 Million records
            int first = 0, last = 0;

            // reads data and make a string of that data
            // which means "data" = "1001011001010100101 .... upto 1 million"
            data = string.Join("", File.ReadAllLines(fileName)); 
            last = Convert.ToInt32("15"); // sequence length
            int l = data.Length;    // calculates it one time so that dont have to do it everytime

            //so why i create List is because sometime Array dont get fully used to its length
            // and get Null values at the end
            List<string> dataList = new List<string>();
            while (first + last < l+1)
            {
                dataList.Add((data.Substring(first, last)));
                first++;
            }
            // converts list to Array so array will have values and no Null
            // and will use Array.FindAll() later
            string[] dataArray = dataList.ToArray(), value;

            // get rready a file to start writing on
            StreamWriter sw = new StreamWriter(fileName.Substring(0, fileName.Length - 4) + "Results.txt");

            //THIS IS THE PART THATS TAKING around 40 minutes
            for (int j = 0; j < dataArray.Length; j++)
            {
                // finds a value in whole array and make array of that finding 
                value = Array.FindAll(dataArray, str => str.Equals(dataArray[j]));
                // value.Length means the count of the Number in the whole array
                sw.WriteLine(value.Length);
            }
            sw.Close();
            time.Stop();
            Console.WriteLine("Time : " + time.Elapsed);
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception " + ex.StackTrace);
            Console.ReadLine();
        }
    }
}

Я установил sequence length = 3, теперь моя программа делает массив:

dataArray = {"011", "110", "100", "001", "010", "101", "011"}

используя String.Substring().Теперь я просто хочу вычислить Frequency элемента массива.

Данные в результирующем .txt файле

011 - 2

110 - 0

100 - 0

001 - 0

010 - 0

101 - 0

011 - 2

Теперь это кажется довольно простым, но это не так, я не могу его преобразовать int, потому что это последовательность, я не хочу терять нули на фронтепоследовательности.

Прямо сейчас моя программа должна зациклить 1 миллион (каждый элемент) X 1 миллион (сравнение с каждым элементом массива) = 1 триллион раз.Это занимает почти 40 минут.Я хочу знать, как я могу сделать это быстро, Parallel.For, TPL Я не знаю о них, как их использовать.Потому что это должно быть сделано за считанные секунды.

Характеристики моей системы

32 ГБ ОЗУ

i7- 5820k 3.30 ГГц

64 бит

2x NVIDIA GTX 970

Ответы [ 2 ]

2 голосов
/ 09 июня 2019

Если я правильно понимаю ваш код и вопрос, вам нужно «сдвинуть окно» (длиной N, last в исходном коде) по тексту и посчитать, сколько раз каждая подстрока существует в тексте. .

Если все верно, следующий код делает это за 0,292 секунды или около того для файла с миллионом символов, и вам совсем не нужен параллелизм или графический процессор.

Идея здесь состоит в том, чтобы подсчитать куски в Dictionary, когда мы перемещаем это окно по тексту.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

public class Program
{
    static Dictionary<string, int> CountChunks(string data, int chunkLength)
    {
        var chunkCounts = new Dictionary<string, int>();
        var l = data.Length;
        for (var i = 0; i < l - chunkLength; i++)
        {
            var chunk = data.Substring(i, chunkLength);
            int count = 0;
            chunkCounts.TryGetValue(chunk, out count);
            chunkCounts[chunk] = count + 1;
        }
        return chunkCounts;
    }
    static void Main(string[] args)
    {
        var time = new Stopwatch();
        time.Start();
        var fileName = "10.txt";
        var data = string.Join("", File.ReadAllText(fileName));
        var chunkCounts = CountChunks(data, 15);
        using (var sw = new StreamWriter(fileName.Substring(0, fileName.Length - 4) + "Results.txt"))
        {
            foreach (var pair in chunkCounts)
            {
                sw.WriteLine($"{pair.Key} - {pair.Value}");
            }
        }
        time.Stop();
        Console.WriteLine("Time : " + time.Elapsed);
    }
}

Вывод 10Results.txt выглядит примерно так:

011100000111100 - 34
111000001111000 - 37
110000011110001 - 27
100000111100010 - 28
000001111000101 - 37
000011110001010 - 36
000111100010100 - 44
001111000101001 - 35
011110001010011 - 41
111100010100110 - 42

и т.д.

РЕДАКТИРОВАТЬ: Вот эквивалентная программа Python. Это немного медленнее, примерно 0,9 секунды.

import time
from collections import Counter

t0 = time.time()
c = Counter()
data = ''.join(l for l in open('10.txt'))
l = 15
for i in range(0, len(data) - l):
    c[data[i : i + l]] += 1

with open('10Results2.txt', 'w') as outf:
    for key, value in c.items():
        print(f'{key} - {value}', file=outf)

print(time.time() - t0)
1 голос
/ 09 июня 2019

Цикл For даст вам ужасную производительность, поскольку он должен проходить цикл сравнения миллионов строк. Я бы предложил использовать словарь вместо списка, чтобы сохранить вашу последовательность в качестве ключа и считать как значение. Это должно дать вам гораздо лучшую производительность по сравнению с циклом while / for. Все, что вам нужно сделать, это немного настроить с точки зрения производительности и, возможно, вам даже не потребуется использовать среду исполнения GPU / TLP, если только это не ваша единственная цель. Что-то внизу должно помочь вам.

       string keyString = string.Empty;
       Dictionary<string,int> dataList = new Dictionary<string,int>;
        while (first + last < l+1)
        {
            keyString = data.Substring(first, last);
            if(dataList.ContainsKey(keyString)
               {
                 dataList[keyString] = dataList[keyString] + 1; 
               }
             else
               {
                 dataList.Add(keyString,1);
               }
            first++;
        }

Остальной код, который вам нужен, это распечатать этот словарь.

...