Усім доброго $(date)!
В якості тестового завдання для компанії писав web crawler -- невеличка програма,
яка зчитує веб-сторінку, витягує лінки та рекурсивно завантажує і знову парсить.
Хочу поділитись досвідом, може комусь згодиться або просто буде цікаво.
На С++ це не така проста задача,
тому згідно поставлених вимог це все має працювати з використанням N потоків а також має бути можливість динамічно міняти їх кількість прямо в процесі парсингу.
sources:
https://github.com/blinkenlichten/test03-v03screenshot(quite primitive UI):
https://raw.githubusercontent.com/blinkenlichten/test03-v03/master/images/screenshot.pngТут вирішувались проблеми:
- ThreadPool, що дозволяє зупинити виконання задач(вони мають вигляд функторів) та експортувати їх у вектор,
а також термінувати виконання задач ASAP.
boost::basic_threadpool, наприклад, може лише "поспівчувати вам" і пропонуює очікувати на завершення всіх задач.
- HTTP client: використовується cURL або NEON. Із Qt5 NetworkManager чомусь не вийшло нічого, і в зневаджувачі я бачив чудеса дивні.
Та й працювати із чистими С-бібліотеками теж корисно.
- atomic pointers: вирішив творити по-менше блокуючого та очікуючого коду(чим менше явної синхронізації -- тим менше потенційних багів із дедлоками; але із lock-free ще треба вчитися працювати), синхронізація відбувається всередині ThreadPool, задачі можуть утворювати під-задачі, щоб передати результати куди-небудь за допомогою функторів.
- html vs regexp? Також спочатку повторив типову помилку молодих програмістів і намагався парсити HTML за допомогою регулярних виразів, були баги, тому переписалось із використанням звичайного пошуку з умовними операторами.
P.S. Усвідомлюю, що така задача вирішується за допомогою Python чи Perl взагалі елементарно,
проте це інтерпретатори, а C/С++ники пишуть там, де необхідна швидкість роботи і економія ресурсів.