Intro

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

Сразу хочу сказать, что многопоточности в PHP нет. Не зря слово многопоточность в заголовке взято в кавычки. Да, существует многопроцессность, реализующаяся средствами операционной системы (этот случай будет разобран), многозадачность, но многопоточности не существует. Однако некоторые задачи все-таки можно выполнять параллельно.

Возьмем пример, встречающийся достаточно часто: скачать программно содержимое нескольких страниц. Если страниц немного, то их можно без проблем и больших затрат времени загрузить последовательно. Но если их тысячи? И вот здесь можно применить подходы, позволяющие выполнить скачивание одновременно. Некоторые из них и будут подробно описаны в данном материале. Сначала мы рассмотрим использование библиотеки curl, которая может производить загрузку одновременно нескольких страниц. Затем попробуем применить к нашей задаче stream-функции. После этого сделаем то же самое с помощью асинхронных сокетов. И наконец распараллелим наш процесс функцией fork.

Все способы проверены на личном опыте. Для примеров взят максимум простой код, без оптимизации, его цель – показать принципы работы каждого метода.

Для вступления рассмотрим такой способ, как

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

Суть состоит в том, что один скрипт вызывается с разными параметрами, разбивающими задачу на несколько одинаковых подзадач.

Пример. Пусть у нас есть скрипт getcontent.php

1
2
3
4
5
6
7
8
9
10
<?php
$urls = array('yandex.ru', 'google.ru', 'rambler.ru', 'bing.com', 'mail.ru');
 
$k = $_GET['k'];
$url = $urls[$k];
$content = file_get_contents('http://'.$url);
$f = fopen($k.'.cont', 'w');
fwrite($f, $content);
fclose($f);
?>

Здесь $urls – массив урлов, содержимое с которых нам надо получить.
Вызывая этот скрипт как getcontent.php?k=n , где n равен какому-либо ключу массива $urls, мы получим на жестком диске файл с именем n.cont, в котором и сохранен html интересующей нас страницы.

Теперь откроем в браузере пять вкладок, напишем в адресной строке первой http://путь/getcontent.php?k=0, адресной строке второй http://путь/getcontent.php?k=1 и т.д. до http://путь/getcontent.php?k=4 и в каждой быстро нажмем Enter. Если теперь зайти в папку с нашим скриптом, то мы увидим там 5 файлов с html сайтов из масива, причем их получение произошло практически (зависит от того, как быстро жать enter) одновременно. Вот на таком нехитром примере мы показали простейший способ выполнения одного задания в несколько "потоков" :)

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

В следующей статье мы попробуем для достижения нашей цели воспользоваться более гуманным способом – использовать библиотеку curl.