Помогите чекнуть 2 миллиарда строк. Как лучше?

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
А можешь действительно проверить на сколько ускорится, если делать HEAD, а не GET запрос? Ну и убрать вывод в лог в самом цикле.
Интересно просто на сколько изменится скорость парсинга именно у тебя, раз уж ты запускал эту версию и выложил скрин замера скорости.
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113
А можешь действительно проверить на сколько ускорится, если делать HEAD, а не GET запрос? Ну и убрать вывод в лог в самом цикле.
Интересно просто на сколько изменится скорость парсинга именно у тебя, раз уж ты запускал эту версию и выложил скрин замера скорости.
лог это я для скрина делал, для себя конечно бы отключил, плюс можно сделать if запись в список, не в каждом потоке а например через 10 потоков чтобы меньше обращаться к спискам
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
как без GET использовать Head ?
Через "синтаксический сахар" от zennolab может проще будет? Там и прокси можно заюзать. Я просто даже не понял почему ты именно на HttpRequest решил написать?

лог это я для скрина делал, для себя конечно бы отключил, плюс можно сделать if запись в список, не в каждом потоке а например через 10 потоков чтобы меньше обращаться к спискам
Да, кстати, тоже скорее всего +10% к скорости будет сразу.
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113
  • Спасибо
Реакции: Lord_Alfred

SergSh

Client
Регистрация
10.05.2017
Сообщения
540
Благодарностей
395
Баллы
63

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113
даже медленее используя

bool status = request.Raw(HttpMethod.HEAD, url).IsOK;

2019-05-06_035930.png

-----------------------------------------------------------------------------------------------

C#:
var useragent = project.Variables["UserAgent"].Value;

int count = 0;
int count2 = 0;
int count3 = 0;

var sb = new StringBuilder();
var pages = new List<object>().Select(t => new { Count = default(int) }).ToList();

for (int i = 0; i < 1000; i++)
{
    count3++;
    pages.Clear();
   
    if (Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) throw new Exception();
    if (((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception();
   
    for (int j = count; j < count2 + 50; j++)
    {
        count++;
        pages.Add(new { Count = count });
    }
    count2 = count;
   
    System.Threading.Tasks.Parallel.ForEach(pages, p =>
    {
        using (var request = new HttpRequest())
        {
            try
            {
                var url = "https://yandex.ru/";
               
                request.ReconnectLimit = 3;
                request.ReconnectDelay = 50;
               
                request.KeepAlive = true;
                request.UserAgent = useragent;
                request.AllowAutoRedirect = true;
                request.IgnoreProtocolErrors = true;
                request.EnableEncodingContent = true;
                request.MaximumAutomaticRedirections = 5;
               
                request["Upgrade-Insecure-Requests"] = "1";
                request["Accept-Language"] = "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7";
                request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3";
               
                bool status = request.Raw(HttpMethod.HEAD, url).IsOK;
           
                if (status)
                {
//                    project.SendInfoToLog("", "Status -> " + status + " -> Count -> " + p.Count.ToString(), true);
                    sb.Append(p.Count.ToString() + "|");
                }
            }
            catch (HttpException e)
            {
                string answer = string.Empty;
                switch (e.Status)
                {
                    case HttpExceptionStatus.Other:
                        answer = "Неизвестная ошибка";
                        break;
                    case HttpExceptionStatus.ProtocolError:
                        answer = "Код состояния: " + (int)e.HttpStatusCode;
                        break;
                    case HttpExceptionStatus.ConnectFailure:
                        answer = "Не удалось соединиться с HTTP-сервером";
                        break;
                    case HttpExceptionStatus.SendFailure:
                        answer = "Не удалось отправить запрос HTTP-серверу";
                        break;
                    case HttpExceptionStatus.ReceiveFailure:
                        answer = "Не удалось загрузить ответ от HTTP-сервера";
                        break;
                }
                project.SendErrorToLog("", answer, true);
            }
        }
    });
   
//    project.SendInfoToLog("", "Обработанно " + count2 + " страгиц", true);
   
    if (count3 == 30 || i == 1000)
    {
        var list = sb.ToString().Split(new string[]{ "|" }, StringSplitOptions.RemoveEmptyEntries);
        FileSystem.FileAppendString(project.Directory + "\\Result.txt", string.Join("\r\n", list), true);
       
        sb.Clear();
        count3 = 0;
    }
}
 
  • Спасибо
Реакции: Lord_Alfred

Geograph

Client
Регистрация
16.02.2014
Сообщения
207
Благодарностей
114
Баллы
43
А если
Код:
bool status = request.Request(HttpMethod.HEAD, url, null).IsOK;
?
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 867
Баллы
113
даже медленее используя
Хмм! Очень странно почему так вышло)
Может он в действительности всё равно весь ответ тащит? Или там на столько быстро он отдается, что этим можно пренебречь
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113
Хмм! Очень странно почему так вышло)
Может он в действительности всё равно весь ответ тащит? Или там на столько быстро он отдается, что этим можно пренебречь
даже не занаю
сейчас добавил по 100, если инет тянет хорошо то можно и 500 вставить, вот результат при 100

2019-05-06_045348.png

C#:
var useragent = project.Variables["UserAgent"].Value;

int count = 0;
int count2 = 0;
int count3 = 0;

var sb = new StringBuilder();
var pages = new List<object>().Select(t => new { Count = default(int) }).ToList();

for (int i = 0; i < 500; i++)
{
    count3++;
    pages.Clear();
   
    if (Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) throw new Exception();
    if (((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception();
   
    for (int j = count; j < count2 + 100; j++)
    {
        count++;
        pages.Add(new { Count = count });
    }
    count2 = count;
   
    System.Threading.Tasks.Parallel.ForEach(pages, p =>
    {
        using (var request = new HttpRequest())
        {
            try
            {
                var url = "https://yandex.ru/";
               
                request.ReconnectLimit = 3;
                request.ReconnectDelay = 50;
               
                request.KeepAlive = true;
                request.UserAgent = useragent;
                request.AllowAutoRedirect = false;
                request.IgnoreProtocolErrors = true;
                request.EnableEncodingContent = false;
                request.MaximumAutomaticRedirections = 5;
               
                request["Upgrade-Insecure-Requests"] = "1";
                request["Accept-Language"] = "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7";
                request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3";
               
                bool status = request.Raw(HttpMethod.HEAD, url, null).IsOK;
           
                if (status)
                {
//                    project.SendInfoToLog("", "Status -> " + status + " -> Count -> " + p.Count.ToString(), true);
                    sb.Append(p.Count.ToString() + "|");
                }
            }
            catch (HttpException e)
            {
                string answer = string.Empty;
                switch (e.Status)
                {
                    case HttpExceptionStatus.Other:
                        answer = "Неизвестная ошибка";
                        break;
                    case HttpExceptionStatus.ProtocolError:
                        answer = "Код состояния: " + (int)e.HttpStatusCode;
                        break;
                    case HttpExceptionStatus.ConnectFailure:
                        answer = "Не удалось соединиться с HTTP-сервером";
                        break;
                    case HttpExceptionStatus.SendFailure:
                        answer = "Не удалось отправить запрос HTTP-серверу";
                        break;
                    case HttpExceptionStatus.ReceiveFailure:
                        answer = "Не удалось загрузить ответ от HTTP-сервера";
                        break;
                }
                project.SendErrorToLog("", answer, true);
            }
        }
    });
   
//    project.SendInfoToLog("", "Обработанно " + count2 + " страниц", true);
   
    if (count3 == 30 || i == 500)
    {
        var list = sb.ToString().Split(new string[]{ "|" }, StringSplitOptions.RemoveEmptyEntries);
        FileSystem.FileAppendString(project.Directory + "\\Result.txt", string.Join("\r\n", list), true);
       
        sb.Clear();
        count3 = 0;
    }
}
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 375
Благодарностей
2 040
Баллы
113
ну и ещё вариант, но тут железо надо хотябы среднее, тестировал на 8-ми ядерном

2019-05-06_050248.png

-------------------------------------------------------------------------------------------------------------

C#:
var useragent = project.Variables["UserAgent"].Value;
//var pageCount = project.Variables["PageCount"].Value;

var sb = new StringBuilder();

System.Threading.Tasks.Parallel.For(0, 50000, (p) =>
{
    if (Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) throw new Exception();
    if (((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception();

    using (var request = new HttpRequest())
    {
        try
        {
            var url = "https://yandex.ru/";
           
            request.ReconnectLimit = 3;
            request.ReconnectDelay = 50;
           
            request.KeepAlive = true;
            request.UserAgent = useragent;
            request.AllowAutoRedirect = false;
//            request.IgnoreProtocolErrors = true;
            request.EnableEncodingContent = false;
            request.MaximumAutomaticRedirections = 5;
           
            request["Upgrade-Insecure-Requests"] = "1";
            request["Accept-Language"] = "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7";
            request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3";
           
            bool status = request.Raw(HttpMethod.HEAD, url, null).IsOK;
       
            if (status)
            {
//                project.SendInfoToLog("", "Status -> " + status + " -> Count -> " + p.Count.ToString(), true);
                sb.Append(p.ToString() + "|");
            }
            else
            {
                project.SendWarningToLog("", "error", true);
            }
        }
        catch (HttpException e)
        {
            string answer = string.Empty;
            switch (e.Status)
            {
                case HttpExceptionStatus.Other:
                    answer = "Неизвестная ошибка";
                    break;
                case HttpExceptionStatus.ProtocolError:
                    answer = "Код состояния: " + (int)e.HttpStatusCode;
                    break;
                case HttpExceptionStatus.ConnectFailure:
                    answer = "Не удалось соединиться с HTTP-сервером";
                    break;
                case HttpExceptionStatus.SendFailure:
                    answer = "Не удалось отправить запрос HTTP-серверу";
                    break;
                case HttpExceptionStatus.ReceiveFailure:
                    answer = "Не удалось загрузить ответ от HTTP-сервера";
                    break;
            }
            project.SendErrorToLog("", answer, true);
        }
    }
});

var list = sb.ToString().Split(new string[]{ "|" }, StringSplitOptions.RemoveEmptyEntries);
FileSystem.FileAppendString(project.Directory + "\\Result.txt", string.Join("\r\n", list), true);
минус что запись только происходит в самом конце при завершении всех потоков
 

Geograph

Client
Регистрация
16.02.2014
Сообщения
207
Благодарностей
114
Баллы
43
Насколько я понимаю System.Threading.Tasks.Parallel.For не запускает сразу все потоки, а ограничивает их сам.
Я попробовал сделать многопоток через обычный Thread там есть разница между Get и Head.
Пример в 50 потоков на 1000 страниц на слабом ПК:

C#:
var threadsCount = 50;
var pages = Enumerable.Range(0, 1000).ToList();
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

var sw = Stopwatch.StartNew();
var threads = new Thread[threadsCount];
for (var i = 0; i < threadsCount; i++)
{
    threads[i] = new Thread(() =>
    {
        while (true)
        {
            var p = 0;
            lock (pages)
            {
                if (pages.Count < 1) return;
                p = pages[0];
                pages.RemoveAt(0);
            }
            var url = "https://yandex.ru/";
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36");
                client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
                client.DefaultRequestHeaders.Add("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7");
                client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
                try
                {                      
                    bool status = (client.GetAsync(url).Result.StatusCode == System.Net.HttpStatusCode.OK);
                    Console.WriteLine($"Page: {p}. Status: {status}");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }){ IsBackground = true, Priority = ThreadPriority.Normal };
    threads[i].Start();      
}

for (var i = 0; i < threadsCount; i++)
{
    threads[i].Join();
}

Console.WriteLine($"{sw.Elapsed}");

GET.png

C#:
var threadsCount = 50;
var pages = Enumerable.Range(0, 1000).ToList();
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

var sw = Stopwatch.StartNew();
var threads = new Thread[threadsCount];
for (var i = 0; i < threadsCount; i++)
{
    threads[i] = new Thread(() =>
    {
        while (true)
        {
            var p = 0;
            lock (pages)
            {
                if (pages.Count < 1) return;
                p = pages[0];
                pages.RemoveAt(0);
            }
            var url = "https://yandex.ru/";
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36");
                client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
                client.DefaultRequestHeaders.Add("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7");
                client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
                try
                {                       
                    var request = new HttpRequestMessage(HttpMethod.Head, url);
                    bool status = (client.SendAsync(request).Result.StatusCode == System.Net.HttpStatusCode.OK);                       
                    Console.WriteLine($"Page: {p}. Status: {status}");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }){ IsBackground = true, Priority = ThreadPriority.Normal };
    threads[i].Start();       
}

for (var i = 0; i < threadsCount; i++)
{
    threads[i].Join();
}

Console.WriteLine($"{sw.Elapsed}");

HEAD.png
 
  • Спасибо
Реакции: Lord_Alfred

luk911

Client
Регистрация
17.01.2013
Сообщения
1 542
Благодарностей
579
Баллы
113
Аhrefs.com - покупаешь акк и парсишь то что живое через апи, и не надо велосипед изобретать. Только проверь есть ли сайт у них в базе.
 

backoff

Client
Регистрация
20.04.2015
Сообщения
6 054
Благодарностей
6 482
Баллы
113

snake

Client
Регистрация
06.07.2015
Сообщения
31
Благодарностей
1
Баллы
8
Господа, раз уж тут зашла речь про чтение больших фалов. Может найдётся какой-нибудь добрый человек который поможет конвертнуть мой PHP код в C#, просто у меня с С# не лады :bw:

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

На время чтения и записи смещения курсора файл блокируется. Чтобы другие процессы не могли его перезаписать. Ну и для создания очереди соответственно.

PHP:
/**
* Функция для совместного чтения файлов построчно
*
* @param $path - Путь к читаемому файлу
* @return bool|string - Прочитанная строка или false - если файл прочитан до конца
*/
function fread($path)
{
    // Получаем абсолютный путь к файлу
    $path = realpath($path);

    // Получаем название папки в которой лежит файл
    $dir = dirname($path);

    // Получаем название файла
    $name = basename($path);

    // Здесь будет хранится прочитанная строка
    $res = false;

    // Открываем файл который  хотим читать (Читаемый файл)
    if ($f_handle = @fopen($path, "rb")) {

        // Открываем или создаём вспомогательный файл который будет хранить смещение курсора в байтах
        // относительно начала читаемого файла (Файл позиций)
        if($p_handle = @fopen($dir . '/' . $name . '.bin', "c+b")) {

            // Ожидаем и получаем блокировку файл позиций, чтобы другие процессы не могли его перезаписать
            if (flock($p_handle, LOCK_EX)) {

                // Переводим курсор в файле позиций в начало файла
                rewind($p_handle);

                // Читаем 4 байта из файла позиций
                // (в этих 4 байтах в бинарном виде хранится смещение курсора от начала читаемого файла)
                $p = fread($p_handle, 4);

                // Получаем последнюю позицию в которую был установлен курсор в читаемом файле
                //
                // Если файл позиций уже существовал и в нём записано смещение курсора читаемого файла,
                // то прекодируем из бинарной системы в int.
                //
                // Если файл позиций только создан и в нём не была записана позиция смещения считаем,
                // что файл читается с начала
                $p = (strlen($p) == 4) ? unpack('i', $p)[1] : 0;

                // Смещаем курсор в читаемом файле в полученную позицию
                fseek($f_handle, $p, SEEK_SET);

                // Читаем строку из читаемого файла
                $res = fgets($f_handle, 5000);

                // Определяем в какой позиции находится курсор после чтения строки
                $p = ftell($f_handle);

                // Кодируем новую позицию в бинарный систему
                $p = pack('i', $p);

                // Переводим курсор в файле позиций в начала файла
                rewind($p_handle);

                // Пишем полученную позицию в файл позиций
                fwrite($p_handle, $p);

                // Сбрасываем буффер вывода в файл
                fflush($p_handle);

                // Снимаем блокировку с файла позиций
                flock($p_handle, LOCK_UN);

                // Закрываем файл позиций
                fclose($p_handle);
            }
        }

        // Закрываем читаемый файл
        fclose($f_handle);
    }

    return $res;
}
 
Последнее редактирование:

snake

Client
Регистрация
06.07.2015
Сообщения
31
Благодарностей
1
Баллы
8
Нет добрых людей? :bn: Или все такие же эксперты по C# как и я? ;-)
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)