C # - улучшить производительность при поиске - PullRequest
0 голосов
/ 02 июля 2018

У меня есть список 15000000 имен пользователей в текстовом файле, и я написал метод для создания из него мозгового кошелька, чтобы проверить, есть ли какой-либо адрес со списком из 600 адресов. Это очень похоже на это

private static List<string> userList = new List<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoUser-workspace-db.txt"));
private static List<string> enterpriseUserList = new List<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoEnterpriseUser-local-db.txt"));
foreach (var i in userList)
{ 
    userid = ToAddress(i);
    if (enterpriseUserList.Contains(userid))
        Console.WriteLine(i,userid);        
    {
    private string ToAddress(string username)
    {
        string bitcoinAddress = BitcoinAddress.GetBitcoinAdressEncodedStringFromPublicKey(new PrivateKey(Globals.ProdDumpKeyVersion, new SHA256Managed().ComputeHash(UTF8Encoding.UTF8.GetBytes(username), 0, UTF8Encoding.UTF8.GetBytes(username).Length), false).PublicKey);     
    }

Метод хэширования имени метода ToAddrsess в строку SHA256, получить его открытый ключ и преобразовать его в адрес следующим образом:

15hDBtLpQfcbrrAFupWjgN5ieHeEBd8mbu

Этот код - задница, работает очень медленно, обрабатывает около 200 строк данных в секунду. Поэтому я пытаюсь улучшить его, используя многопоточность

private static void CheckAddress(string username)
{                      
    var userid = ToAddress(username);
    if (enterpriseUserList.Contains(userid))
    {
        Console.WriteLine(i,userid);        
    }            
}
private static void Parallel() 
{
    List<string> items = new List<string>(File.ReadLines(@"C:\Users\Erik\Desktop\InfernoUser-workspace-db.txt"));
    ParallelOptions check = new ParallelOptions() { MaxDegreeOfParallelism = 100 };
    Parallel.ForEach<string>(items, check, line =>
    {
        CheckAddress(line);
    });
}

Это не сильно помогло. Кто-нибудь может подсказать, как это импровизировать? сравните с vanitygen, работающим на CPU, который может обрабатывать 4-500 тыс. адресов в секунду. Как это может иметь такое большое значение?

Ответы [ 3 ]

0 голосов
/ 02 июля 2018

При поиске неэффективности одним из основных красных флажков является повторный вызов функции. Вы звоните GetBytes дважды. Помещение в отдельную переменную и один раз вызов должен помочь кое-чему.

private string ToAddress(string username)
{
    var userNameAsBytes = UTF8Encoding.UTF8.GetBytes(username);
    string bitcoinAddress = BitcoinAddress.GetBitcoinAdressEncodedStringFromPublicKey(new PrivateKey(Globals.ProdDumpKeyVersion, new SHA256Managed().ComputeHash(userNameAsBytes, 0, userNameAsBytes.Length), false).PublicKey);     
}
0 голосов
/ 03 июля 2018

Вы можете выполнить некоторые операции здесь

  1. обновление List до HashSet. он будет резко выполнять Contains операций. Я уверен, что это самый медленный случай в этой кодовой базе. private static List<string> enterpriseUserList = new List<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoEnterpriseUser-local-db.txt")); изменить на private static HashSet<string> enterpriseUserList = new HashSet<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoEnterpriseUser-local-db.txt"));
  2. не используйте ParallelOptions check = new ParallelOptions() { MaxDegreeOfParallelism = 100 }; этот тип оптимизации увеличит скорость переключения контекста и снизит производительность.
  3. оптимизировать Parallel.ForEach, используя Partitioner.Create

Может быть, это все, что я могу вам посоветовать.

    private static List<string> userList = new List<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoUser-workspace-db.txt"));
    private static HashSet<string> enterpriseUserList = new HashSet<string>(File.ReadAllLines(@"C:\Users\Erik\Desktop\InfernoEnterpriseUser-local-db.txt"));

 [MethodImpl(MethodImplOptions.AggressiveInlining)]
   private static void CheckAddress(int id,string username)
{                      
    var userid = ToAddress(username);
    if (enterpriseUserList.Contains(userid))
    {
       // todo
    }            
}


private static void Parallel() 
{
    var ranges = Partitioner.Create(0,userList.Count);
    Parallel.ForEach(ranges ,(range)=>{
     for(int i=range.Item1;i<range.Item2;i++){
              CheckAddress(i,userList[i])               
     }}

}
0 голосов
/ 02 июля 2018

Вы можете попробовать использовать словарь с ключом = идентификатор пользователя, чтобы запретить поиск по списку на каждой итерации

var dict = new ConcurrentDictionary<string, string>(100, userList.Count);

        userList.AsParallel().ForAll(item => 
        {
            dict.AddOrUpdate(ToAddress(item), item, (key,value)=>{return value;});
        });

        enterpriseUserList.AsParallel().ForAll(x =>
        {
            if (dict.ContainsKey(x))
            { Console.WriteLine(dict[x]); }
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...