Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как ускорить libcurl? / 25 сообщений из 31, страница 1 из 2
29.04.2017, 15:09
    #39446542
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Загружаю страницу с помощью curl двумя способами:

libcurl
system("curl")

Код первого способа:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
/**
Коллбэк функция для curl
*/
size_t curlClbck( char *ptr, size_t size, size_t nmemb, std::string* data){
  if (data) {
    data->append(ptr, size*nmemb);
    return size*nmemb;
  }
  else return 0;
}

/**
 * Получает содержимое страницы по ссылке link
 * @param link Ссылка на страницу
 * @return Строка с содержимым страницы
 */
std::string curlGet(string link){
  std::cout << "Read to memory" << '\n';
  CURL *curl;
  std::string content;
  curl = curl_easy_init();
  if(curl){
    curl_easy_setopt(curl, CURLOPT_URL, link.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlClbck);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
    CURLcode res = curl_easy_perform(curl);
    if (res == CURLE_OK) {
      curl_easy_cleanup(curl);
      return content;
    }else std::cerr << curl_easy_strerror(res) << std::endl;
    curl_easy_cleanup(curl);
  }
  return "";
}



Код второго способа:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
  /**
   * Скачивает страницу по ссылке link в файл,
   * затем считывает файл в строку
   * @param link Ссылка на страницу
   * @return Строка с содержимым страницы
   */
  std::string systemGet (std::string link) {
    std::cout << "Read to file" << '\n';
    std::string res = "";
    string curl = "curl -o curl.html '" + link + "' -k > /dev/null 2>&1";
    system(curl.c_str());
    /*
      Здесь код считывания файла в строку res
      приводить его не буду, ибо он прост, но объёмен
    */
    return res;
  }



Тестируем функции:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
  unsigned int start_time, end_time,work_time;
  
  start_time = clock();
  std::string tmp1 = gurlGet(link);
  end_time = clock();
  work_time = end_time - start_time;
  cout << "Libcurl time: " << work_time << '\n'; 
    
  start_time =  clock();
  std::string tmp2 = systemGet(link);
  end_time = clock();
  work_time = end_time - start_time;
  cout << "System  time: " << work_time << '\n'; 

  cout << "Length tmp1: " << std::to_string(tmp1.length()) << '\n';
  cout << "Length tmp2: " << std::to_string(tmp2.length()) << '\n';



Вывод:

Код: plaintext
1.
2.
3.
4.
5.
Read to memory
Libcurl time: 20379
Read to file
System  time: 4646
Length tmp1: 114953
Length tmp2: 114953

Удивительно, но факт: скачать страницу в файл и считать из него в строку получается в 3 раза быстрее! Почему так медленно работает libcurl по сравнению с вызовом внешней программы?
...
Рейтинг: 0 / 0
29.04.2017, 15:44
    #39446550
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
В экспериментах надо учитывать эффект прогрева сети, проксей и состояния ОС.
Я-бы предложил сделать явный запуск двух функций хотя-бы 5 или 7 раз чередуя
их через чет-нечёт и усреднить время.

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

Иногда - дьявол в деталях.
...
Рейтинг: 0 / 0
29.04.2017, 16:00
    #39446554
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
14:09, axsmak
Код: sql
1.
2.
     data->append(ptr, size*nmemb);
     return size*nmemb;



Дай угадаю: считывание идёт по одному символу?..
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
29.04.2017, 16:25
    #39446560
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
maytonВ экспериментах надо учитывать эффект прогрева сети, проксей и состояния ОС.
Я-бы предложил сделать явный запуск двух функций хотя-бы 5 или 7 раз чередуя
их через чет-нечёт и усреднить время.
Я сначала написал "ленивый вариант" с system и прогнал десяток страниц в цикле.
Потом, в надежде на ускорение, написал функцию на libcurl и тот же цикл отработал гораздо медленнее. Поэтому и начал проводить тесты и замеры.
Тесты запускались не раз и в разных комбинациях. Результат один.

maytonПлюс я-бы заметил что загадочный закомментированный код где читается файл
в строку может содержать ошибки которые приводят к замедлениям.
В том-то и подвох, что эта функция работает гораздо быстрее.
Код: sql
1.
2.
3.
4.
5.
6.
7.
  int i=0;
  std::ifstream f(fname);
  while (!f.eof()) {
    f.get(s[i]);
    i++;
  }
  f.close();
...
Рейтинг: 0 / 0
29.04.2017, 16:32
    #39446562
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Dimitry SibiryakovДай угадаю: считывание идёт по одному символу?..

Это коллбэк. Привязан тут: curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlClbck);
ptr - указатель на принимаемые данные.
size - размер принимамого блока данных
nmemb - общее количество блоков данных, объем принимаемой информации определяется как size * nmemb
То есть size определяет сам curl
К тому же в предыдущем комментарии я показал код считывания из файла. Там точно по одному символу. Вполне справедливо для теста
...
Рейтинг: 0 / 0
29.04.2017, 17:28
    #39446577
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
axsmak,

еще есть вариант, что твое приложение линкует дебаг(неоптимизированную) версию курла, а исполняет релиз(оптимизированную)

но 20с против 4с - это больше похоже на dns resolve или что то такое
...
Рейтинг: 0 / 0
29.04.2017, 17:39
    #39446580
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Может дело в этом:
Код: plaintext
1.
end_time = clock();


clock() в линуксе меряет время работы процессора, т.е. запустив другой процесс через system() время останавливается.

Попробуй заменить clock() на std::chrono
Например так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
// Время с момента первого вызова, мсек
static int64_t lite_time_now() {
	static std::chrono::steady_clock::time_point t = std::chrono::steady_clock::now();
	std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
	std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t);
	return (int64_t)(time_span.count() * 1000);
}

...
Рейтинг: 0 / 0
29.04.2017, 18:01
    #39446586
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
axsmak
Код: sql
1.
2.
3.
4.
5.
6.
7.
size_t curlClbck( char *ptr, size_t size, size_t nmemb, std::string* data){
  if (data) {
    data->append(ptr, size*nmemb);
    return size*nmemb;
  }
  else return 0;
}


Тут может быть тормоз если curlClbck() многократно вызывается во время скачивания одного файла. Т.к. string::append() выделяет память под новую строку и делает копию каждый раз.

Попробуй сразу зарезервировать сколько надо
Код: plaintext
1.
2.
3.
4.
std::string curlGet(string link){
...
  std::string content;
  content.reserve(1000000);
...
Рейтинг: 0 / 0
29.04.2017, 18:08
    #39446588
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Для чистоты эксперимента лучше вообще замени добавление в строку на запись в файл. Тогда твой код будет делать тоже самое что и system("curl")
...
Рейтинг: 0 / 0
30.04.2017, 00:16
    #39446664
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Функция curlGet() не монолитна. Она состоит из нескольких последовательно вызываемых методов libcurl
каджый из которых потребляет своё время. Эти 20379 милисекунд распределены неоднородно по этим
методам.

Неплохо было-бы детализировать сколько сколько каждый занял.

Далее получив картинку - подумаем почему много потребляет основной потребитель. Здесь
могут быть варианты. Синхронность-асинхронность. Utf-0/ISO-8859-1.

И не точная аналогия между system("curl....") и котом который использует curl_eazy. Почему мы решили
что он эквивалентен? ХЗ.
...
Рейтинг: 0 / 0
30.04.2017, 07:06
    #39446690
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
maytonПочему мы решили
что он эквивалентен? ХЗ.
По эквивалентному результату.
...
Рейтинг: 0 / 0
30.04.2017, 10:27
    #39446702
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Самое верное замечание было дано Dima T - clock() замеряет процессорное время используемое моим приложением. Во время выполнения внешней программы curl моё приложение почти не использует процессорное время.

С применением его lite_time_now() тесты показали примерно следующее время:
libcurl - 700 мск

system - 550 мск

Затем я изменил тест, прогоняя 10 разных страниц в цикле. И прогонял цикл несколько раз c разрывом в пару секунд. Так вот, цикл с system всегда показывает 5400-6000 мск, а libcurl в первый цикл показывает 7500-8000 мск, а последуюющие 5000-5200 мск. Стоит подождать некоторое время и libcurl опять остывает.

Кстати, до тестов я сделал резервирование памяти под строку результата content.reserve(1000000); Потом убрал её и скорость незначительно, но возрасла. Теперь libcurl, после разогрева показывает 4800-5000 мск, что, наконец-то превосходит system

Теперь осталось разобраться почему libcurl тормозит во время первого запуска. Какие мысли будут, господа?
...
Рейтинг: 0 / 0
30.04.2017, 10:38
    #39446704
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
axsmakТеперь осталось разобраться почему libcurl тормозит во время первого запуска. Какие мысли будут, господа?
К DNS обращается при первом вызове. При последующих к локальному кэшу. Поставь первым вызов system(), будет на нем тормозить.
...
Рейтинг: 0 / 0
30.04.2017, 10:43
    #39446706
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Логи тестов
libcurl первый запуск
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
База создана
----------------
Page 1 begin 
Read to memory
Page 1 end 
Record count 50
----------------
Page 2 begin 
Read to memory
Page 2 end 
Record count 50
----------------
Page 3 begin 
Read to memory
Page 3 end 
Record count 50
----------------
Page 4 begin 
Read to memory
Page 4 end 
Record count 50
----------------
Page 5 begin 
Read to memory
Page 5 end 
Record count 50
----------------
Page 6 begin 
Read to memory
Page 6 end 
Record count 50
----------------
Page 7 begin 
Read to memory
Page 7 end 
Record count 50
----------------
Page 8 begin 
Read to memory
Page 8 end 
Record count 12
----------------
Page 9 begin 
Read to memory
Page 9 end 
Record count 0
----------------
Cycle time: 7957
База успешно разрушена

ВЫПОЛНЕНИЕ FINISHED; значение выхода 0,; в реальном времени: 7s; пользователь: 20ms; система: 340ms


libcurl следующий запуск
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
База создана
----------------
Page 1 begin 
Read to memory
Page 1 end 
Record count 50
----------------
Page 2 begin 
Read to memory
Page 2 end 
Record count 50
----------------
Page 3 begin 
Read to memory
Page 3 end 
Record count 50
----------------
Page 4 begin 
Read to memory
Page 4 end 
Record count 50
----------------
Page 5 begin 
Read to memory
Page 5 end 
Record count 50
----------------
Page 6 begin 
Read to memory
Page 6 end 
Record count 50
----------------
Page 7 begin 
Read to memory
Page 7 end 
Record count 50
----------------
Page 8 begin 
Read to memory
Page 8 end 
Record count 12
----------------
Page 9 begin 
Read to memory
Page 9 end 
Record count 0
----------------
Cycle time: 5766
База успешно разрушена

ВЫПОЛНЕНИЕ FINISHED; значение выхода 0,; в реальном времени: 5s; пользователь: 10ms; система: 320ms


system любой запуск
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
База создана
----------------
Page 1 begin 
Read to file
Page 1 end 
Record count 50
----------------
Page 2 begin 
Read to file
Page 2 end 
Record count 50
----------------
Page 3 begin 
Read to file
Page 3 end 
Record count 50
----------------
Page 4 begin 
Read to file
Page 4 end 
Record count 50
----------------
Page 5 begin 
Read to file
Page 5 end 
Record count 50
----------------
Page 6 begin 
Read to file
Page 6 end 
Record count 50
----------------
Page 7 begin 
Read to file
Page 7 end 
Record count 50
----------------
Page 8 begin 
Read to file
Page 8 end 
Record count 12
----------------
Page 9 begin 
Read to file
Page 9 end 
Record count 0
----------------
Cycle time: 6178
База успешно разрушена

ВЫПОЛНЕНИЕ FINISHED; значение выхода 0,; в реальном времени: 6s; пользователь: 70ms; система: 410ms
...
Рейтинг: 0 / 0
30.04.2017, 10:47
    #39446707
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Dima TК DNS обращается при первом вызове. Реально ли программно реализовать что-то вроде кэша dns или просто забить на это?
Просто напрягает, что тормозит весь цикл, а не, хотя бы, первый вызов функции
...
Рейтинг: 0 / 0
30.04.2017, 10:51
    #39446709
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Dima T, Совершенно верно
авторCURLOPT_DNS_CACHE_TIMEOUT - set life-time for DNS cache entries
By default, libcurl caches this info for 60 seconds.
...
Рейтинг: 0 / 0
30.04.2017, 11:46
    #39446717
axsmak
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Всё нашёл.
Код: plaintext
1.
curl_easy_setopt(curl, CURLOPT_RESOLVE, host);


Жёстко прописал айпи сервера в настройки курл.
Кроме того вынес инициализацию из функции и вызываю в начале работы.
Определил неймспейс для работы с курлом, где написал функции инициализации, закрытия и выполнения запроса.
Скорость возросла в полтора раза в сравнении с system
Всем спасибо, код прилагаю

Буст libcurl
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
namespace crl {  
  CURL *curl;
  std::string content;
  struct curl_slist *host=NULL; 
  
  bool prepare () {
    curl = curl_easy_init();
    if (curl) {
      host = curl_slist_append(host, "host.com:443:222.222.222.222");
      curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlClbck);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
      std::cout << "Curl prepared" << '\n';
      return true;
    } else return false;
  }
  
  void close () {
    if (curl) {
      curl_easy_cleanup(curl);
      std::cout << "Curl closed" << '\n';
    }
  }

  size_t curlClbck( char *ptr, size_t size, size_t nmemb, string* data){
    if (data) {
      data->append(ptr, size*nmemb);
      return size*nmemb;
    } else return 0;
  }
  
  string exec(string link){
    content = "";
    if(curl){
      curl_easy_setopt(curl, CURLOPT_URL, link.c_str());
      CURLcode res = curl_easy_perform(curl);
      if (res == CURLE_OK) {
        return content;
      }else std::cerr << curl_easy_strerror(res) << std::endl;    
    }
    return "";
  }
}

int main(int argc, char** argv) {
  crl::prepare();
  /*
    Работа в цикле с crl::exec(link);
  */
  crl::close();
}

...
Рейтинг: 0 / 0
30.04.2017, 14:22
    #39446738
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
axsmak,

почему не сделать
CURL *curl = nullptr;
?

иначе довольно опасно. значение переменно не определено, но производится проверка.
если там будет "мусор" проверка может пройти, но работать не будет(в лучшем случае).

Ну и не понимаю я таких проверка на nullptr как
if(curl){

почему не сделать явное условие?
видимо, -Wall -Werror не используются
...
Рейтинг: 0 / 0
30.04.2017, 15:27
    #39446745
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
alex_kНу и не понимаю я таких проверка на nullptr как
if(curl){

почему не сделать явное условие?
видимо, -Wall -Werror не используются
Это идиома с/с++. С чего вдруг должны быть предупреждения?
...
Рейтинг: 0 / 0
30.04.2017, 16:28
    #39446748
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
axsmakЖёстко прописал айпи сервера в настройки курл.
IP поменяется и долго будешь искать почему работать перестало.
...
Рейтинг: 0 / 0
30.04.2017, 16:42
    #39446751
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Anatoly Moskovskyalex_kНу и не понимаю я таких проверка на nullptr как
if(curl){

почему не сделать явное условие?
видимо, -Wall -Werror не используются
Это идиома с/с++. С чего вдруг должны быть предупреждения?
да, нет варнинга. а я бы сделал! :)
чтобы в условиях был только буль
...
Рейтинг: 0 / 0
30.04.2017, 16:53
    #39446754
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
alex_kAnatoly Moskovskyпропущено...

Это идиома с/с++. С чего вдруг должны быть предупреждения?
да, нет варнинга. а я бы сделал! :)
чтобы в условиях был только буль
0, NULL и false это одно и тоже. Это просто надо знать если пишешь на С/С++.
...
Рейтинг: 0 / 0
30.04.2017, 17:30
    #39446757
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Dima Talex_kпропущено...

да, нет варнинга. а я бы сделал! :)
чтобы в условиях был только буль
0, NULL и false это одно и тоже. Это просто надо знать если пишешь на С/С++.
при это NULL - это просто символьное имя, которое может быть чем угодно :)
Это тоже надо знать :)
...
Рейтинг: 0 / 0
30.04.2017, 17:38
    #39446758
alex_k
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
Код: plaintext
1.
2.
3.
4.
5.
6.
int main()
{
    float NULL = 3.14f;
    if (NULL) throw "what?";
    return 0;
}
...
Рейтинг: 0 / 0
30.04.2017, 17:58
    #39446761
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить libcurl?
alex_k
Код: plaintext
1.
2.
3.
4.
5.
6.
int main()
{
    float NULL = 3.14f;
    if (NULL) throw "what?";
    return 0;
}


Не компилируется.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как ускорить libcurl? / 25 сообщений из 31, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]