<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Работа для  программистов &#187; многопоточность</title>
	<atom:link href="http://job-interview.ru/articles/post/tag/%d0%bc%d0%bd%d0%be%d0%b3%d0%be%d0%bf%d0%be%d1%82%d0%be%d1%87%d0%bd%d0%be%d1%81%d1%82%d1%8c/feed" rel="self" type="application/rss+xml" />
	<link>http://job-interview.ru/articles</link>
	<description>вакансии, вопросы, статьи</description>
	<lastBuildDate>Thu, 29 Mar 2012 20:53:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>“Многопоточность” в PHP (socket)</title>
		<link>http://job-interview.ru/articles/post/194</link>
		<comments>http://job-interview.ru/articles/post/194#comments</comments>
		<pubDate>Sun, 27 Dec 2009 13:21:34 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[асинхронные сокеты]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[неблокирующие сокеты]]></category>

		<guid isPermaLink="false">/articles/?p=194</guid>
		<description><![CDATA[Использование асинхронных сокетов.
Предлагаю вашему вниманию третью статью из цикла &#8220;Многопоточность&#8221; в  PHP. В данной статье мы рассмотрим асинхронные или неблокирующие сокеты.
Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование асинхронных сокетов.</h3>
<p>Предлагаю вашему вниманию третью статью из цикла <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в  PHP</a>. В данной статье мы рассмотрим <strong>асинхронные</strong> или <strong>неблокирующие сокеты</strong>.</p>
<p>Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у нас много и с ними производятся одинаковые действия. Хорошо, если бы можно было не дожидаться завершения соединения, а сразу же открывать следущее. И такая возможность существует.</p>
<p>Но сначала давайте разберем само <strong>понятие &#8220;сокет&#8221;</strong>. Что такое сокет?<br />
<span id="more-194"></span></p>
<blockquote><p><strong>Сокеты</strong>  — это название программного интерфейса для обеспечения информационного обмена между <em>процессами</em>. Процессы при таком обмене могут исполняться как на одном компьютере, так и на различных, связанных между собой сетью. <strong>Сокет</strong> — абстрактный объект, представляющий конечную точку соединения.</p></blockquote>
<p>В нашем случае сокет будет представлять собой соединение между нашей программой и компьютером, с которого требуется получить необходимую информацию.</p>
<p><em>Работа с сокетами</em> достаточно проста:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// создаем сокет</span>
<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// открываем сокет</span>
<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'80'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// записываем данные в сокет</span>
<span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #339933;">,</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// читаем данные из сокета</span>
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Сначала <em>функцией socket_create</em> инициализируем сокет и задаем его характеристики – флаг AF_INET, переданный в качестве первого параметра, указывает, что создается  сокет для интернета, второй параметр – тип сокета (самые распространенные – TCP и UDP)  нам нужен TCP-сокет &#8211; SOCK_STREAM, и третий параметр задает протокол (TCP).<br />
Затем с помощью <em>функции socket_connect</em> происходит соединение к указанному адресу и порту. Надо заметить, что эта функция принимает в качестве параметра не сам адрес хоста, а его ip адрес, поэтому сначала мы должны его определить <em>функцией gethostbyname</em>.<br />
Теперь нам надо <strong>сформировать запрос</strong>, который мы отправим на сервер (подробнее о <strong>http-заголовках</strong> можно почитать в <a href="/articles/post/86" target="_blank">статье PHP и HTTP</a>). Собственно отправку производит <em>функция socket_write</em>, второй параметр которой – это то, что мы отправляем и третий – длина отправляемой строки (т.е. всех сформированных заголовков).<br />
Запись произведена, теперь <em>функцией socket_read</em> читаем данные, переданные для нас сервером.<br />
В результате в переменной $result хранится хтмл, который нам необходим.</p>
<p>Задача у нас стоит та же, что и в предыдущих примерах: <em>получить содержимое нескольких html-страниц</em>. Вот код, реализующий это:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
	<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// таймаут для чтения</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_RCVTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут для записи</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_SNDTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// задаем неблокирующий режим сокетов</span>
	<span style="color: #990000;">socket_set_nonblock</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
	<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// соединяемся</span>
	<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">80</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
	<span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// продолжаем, пока есть задачи для записи или чтения</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
	<span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
	<span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
	<span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
			<span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
			<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #666666; font-style: italic;">// записываем в сокет</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
			<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// закрываем сокет</span>
			<span style="color: #990000;">socket_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// заносим html в массив результатов</span>
			<span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Можно заметить, что код несильно отличается от <a href="/articles/post/92#stream_code" target="_blank">кода для stream-функций</a>.</p>
<p>В общих словах здесь происходит следующее. Каждый сокет <em>инициализируется</em> и переводится в <em>неблокирующий режим</em>. Затем в цикле производится проверка готовых к чтению или записи сокетов, и если такие существуют, производится соответствующая операция. Все действия протекают в <em>асинхронном порядке</em>, т.е не ждут окончания предыдущей операции. Например, если данные с мэйл.ру поступили раньше, чем от яндекса, то будут обрабатываться именно они, хотя коннект к яндексу мог произойти до коннекта к мэйлу. Можно сказать, что все происходит в несколько &#8220;потоков&#8221;, когда параллельно ожидается готовность каждого сокета к какому-либо действию.</p>
<p>Теперь разберем код более подробно.<br />
Итак, у нас есть массив с адресами страниц. В строке 9 запускается цикл для инициализации соединения с каждым хостом. В 11 строке создается сокет, затем в 15 и 17 строках мы задаем таймауты для чтения и записи соответственно. В 19 строчке <em>функцией socket_set_nonblock</em> задаем <strong>неблокирующий режим,</strong> превращающий каждый наш сокет в <strong>асинхронный</strong>. Это необходимо для того, чтобы после очередной операции над сокетом не происходило ожидание ее окончания, а продолжал работу остальной код программы. В 26 строке заносим инициализированный сокет в массив сокетов для записи.</p>
<p>Основной цикл начинается в 30 строчке. Он будет продолжаться до тех пор, пока у нас остаются сокеты, в которые нужно записать или из которых надо прочитать.<br />
В 32 строке массиву $rtasks_ присваиваем массив сокетов, из которых должна быть прочитана информация. В 34-ой в $wtasks_ заносится массив с сокетами, в которые необходимо произвести запись.<br />
Главная функция в этом цикле &#8211; <em>socket_select</em>. Она принимает на вход массивы сокетов, ожидающих чтения, ожидающих запись и массив для исключительных ситуаций, четвертый параметр, передаваемый в данную функцию – таймаут. Параметры-массивы передаются по ссылке, т.е когда произойдет ожидаемое событие (<em>socket_select</em> в этом случае вернет число больше 0), в них появятся соответствующие дескрипторы.<br />
Если нашлись сокеты, доступные для записи, ищем урл, соответствующий каждому из готовых сокетов, и <em>функцией socket_write</em> записываем в него заголовки для получения хтмл страницы в ответе. Так же в 44-ой строке удаляем дескриптор из массива для записи, так как она будет произведена, и заносим его в строке 46 в массив для чтения, чтобы потом получить интересующий нас ответ.<br />
Если же имеются сокеты, готовые нам ответить, считываем из них информацию <em>функцией socket_read</em>.<br />
Profit! В массиве $results содержится вожделенный хтмл-код!</p>
<p><b>Замечание:</b><br />
<i>При вызове функции socket_connect, когда сокет переведен в неблокирующий режим функцией socket_set_nonblock, выдается предупреждение <b style="color: red;">&#8220;Operation now in progress&#8221; (&#8221;Операция на незаблокированном сокете не может быть завершена немедленно&#8221;)</b>, а socket_connect возвращает false. Несмотря на это, код нормально отрабатывает.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/194/feed</wfw:commentRss>
		<slash:comments>12569</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (stream)</title>
		<link>http://job-interview.ru/articles/post/92</link>
		<comments>http://job-interview.ru/articles/post/92#comments</comments>
		<pubDate>Tue, 28 Jul 2009 07:24:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[stream]]></category>
		<category><![CDATA[stream_socket]]></category>
		<category><![CDATA[многопоточность]]></category>

		<guid isPermaLink="false">/articles/?p=92</guid>
		<description><![CDATA[Использование stream-функций.
Это вторая статья из серии “Многопоточность” в PHP.
В прошлый раз мы рассмотрели curl, теперь давайте поговорим о stream-функциях.

Вольный перевод документации:
Streams (потоки) были введены в PHP 4.3.0 как способ обобщить работу с файлами, сетью, сжатием данных и другими процессами, которые совместно используют единый набор функций. В простейшем определении, поток – объект ресурса, имеющий &#8220;потокообразное&#8221; поведение, [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование stream-функций.</h3>
<p>Это вторая статья из серии <a href="/articles/post/62" target="_blank">“Многопоточность” в PHP</a>.</p>
<p>В <a href="/articles/post/67" target="_blank">прошлый раз</a> мы рассмотрели <em>curl</em>, теперь давайте поговорим о <strong>stream-функциях</strong>.</p>
<p>
Вольный перевод документации:</p>
<blockquote><p><strong>Streams</strong> (потоки) были введены в PHP 4.3.0 как способ обобщить работу с файлами, сетью, сжатием данных и другими процессами, которые совместно используют единый набор функций. В простейшем определении, поток – объект ресурса, имеющий &#8220;потокообразное&#8221; поведение, т.е. из которого можно читать, в который можно писать и внутри которого можно перемещаться.</p></blockquote>
<p><strong>stream_socket-функции</strong> являются частью streams, при помощи них мы можем коннектиться или писать/читать данные, <em>не дожидаясь завершения предыдущей операции</em>.</p>
<p><span id="more-92"></span></p>
<p>Итак, <em>дано</em>: массив с урлами. <em>Задача</em>: непоследовательно получить их содержимое.</p>
<p>Давайте рассмотрим код, который решает поставленную нами задачу:</p>
<p><a name="stream_code"></a></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
    <span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">stream_socket_client</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">':80'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errno</span><span style="color: #339933;">,</span> <span style="color: #000088;">$errstr</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span>
        STREAM_CLIENT_ASYNC_CONNECT<span style="color: #339933;">|</span>STREAM_CLIENT_CONNECT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
    <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
    <span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
    <span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
    <span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">stream_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
            <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
            <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
            <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
            <span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Encoding: gzip,deflate<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// записываем в сокет</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
            <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
            <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fread</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">8192</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// закрываем сокет</span>
            <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
            <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">// заносим html в массиы результатов</span>
            <span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>
 Сначала инициализируются три массива: $rtasks – в него будут заноситься сокеты, из которых можно читать данные, $wtasks – для сокетов, готовых к записи, и $results – массив для сохранения содержимого заданных страниц.</p>
<p>
Затем в цикле <em>функцией stream_socket_client</em> открываются сокеты для каждого из урлов, при этом ставится флаг STREAM_CLIENT_ASYNC_CONNECT, который указывает, что каждое следующее соединение надо открывать <strong>не дожидаясь завершения открытия предыдущего</strong>. Флаг STREAM_CLIENT_CONNECT указывает, что мы создаем именно клиентское подключение.<br />
Дескрипторы сокетов заносятся в массив $wtasks.</p>
<p>В 18-ой строке начинается главный цикл, и сразу массивам $rtasks_ и $wtasks_, передаваемым в функцию stream_select, присваиваются массивы, в которых хранятся сокеты для чтения и записи соответственно. <em>Функция stream_select</em> отслеживает наличие данных в потоках и принимает на вход несколько параметров: первый – это массив дескрипторов, в которых ожидается завершение операции чтения, второй – массив с дескрипторами, ожидающими завершение записи, третий – для особых случаев (поступление &#8220;out-of-band data&#8221; &#8211; внеполосных данных) и четвертый параметр &#8211; это таймаут.  Массивы передаются в функцию по указателям, и как только функция возвращает число больше 0, в них будут находится сокеты, готовые к действиям.</p>
<p>В 28-ой строке мы смотрим, в какие сокеты можно записать данные (надо что-то отправить, прежде чем нам придет ответ-результат), и если такие сокеты есть, то удаляем из массива для записи текущий дескриптор, помещаем его в массив для чтения, и отправляем заголовки, необходимые для получения контента.<br />
Далее, в 49-ой строчке, просматриваем сокеты, готовые для считывания из них данных, забираем содержимое, удаляем дескриптор из масива для чтения и закрываем сокет. Результат заносим в массив $results. Повторяем эти операции до тех пор, пока у нас остаются какие-либо открытые сокеты.</p>
<p>После работы скрипта нужный нам контент находится в массиве $results.</p>
<p>В статье рассмотрен пример работы с <strong>функциями stream_socket_*</strong>, на очереди <a href="/articles/post/194" target="_blank">асинхронные сокеты</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/92/feed</wfw:commentRss>
		<slash:comments>108</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (curl)</title>
		<link>http://job-interview.ru/articles/post/67</link>
		<comments>http://job-interview.ru/articles/post/67#comments</comments>
		<pubDate>Thu, 09 Jul 2009 07:09:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[мультизапросы]]></category>

		<guid isPermaLink="false">/articles/?p=67</guid>
		<description><![CDATA[Использование библиотеки curl.
Эта статья является первой из серии &#8220;Многопоточность&#8221; в PHP

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

Используем [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование библиотеки curl.</h3>
<p>Эта статья является первой из серии <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в PHP</a></p>
<p>
<strong>Curl</strong> – это библиотека, позволяющая подсоединяться к разным серверам по разным протоколам. Обладает удобством в работе и способностью гибко настраиваться.<br />
Curl реализует механизм <em>множественных запросов</em>, или <em>мультизапросов</em>. Его принцип заключается в том, что посылается несколько запросов, при этом перед отправкой следующего не ожидается ответ на предыдущий.
</p>
<p>Используем это в нашем примере <strong>скачивания нескольких страниц</strong>.
</p>
<p>Рассмотрим сначала процесс <em>скачивания содержимого с одного url</em>. </p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// инициализация сеанса curl</span>
<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// curl_exec будет возвращать результат</span>
<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// не будет возвращаться http-заголовок</span>
<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// загрузка страницы и выдача её браузеру</span>
<span style="color: #000088;">$content</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// завершение сеанса и освобождение ресурсов</span>
<span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>
Здесь <em>функцией curl_init</em> мы инициализируем сеанс curl и в качестве параметра передаем урл страницы, которую хотим скачать. Далее первым вызовом <em>функции curl_setopt</em> говорим, что результат надо вернуть, а не вывести в браузер, и вторым запрещаем передачу нам http-ответа сервера. curl_setopt принимаюет в качестве параметров дескриптор соединения $ch, название опции и ее значение соответственно. С помощью curl_setopt можно задать много параметров для более тонкого управления соединением, подробнее читайте в <a href="http://php.net/curl" target="_blank">мануале</a> к этой библиотеке. Затем <em>функцией curl_exec</em> производим собственно скачивание и в завершении закрываем соединение &#8211; <em>curl_close</em>. В переменной $content у нас теперь находится код страницы, указанной в $url.
</p>
<p>А сейчас давайте попробуем <strong>скачать сразу несколько страниц</strong> (основа примера взята из документации на php.net):
</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// инициализируем &quot;контейнер&quot; для отдельных соединений (мультикурл)</span>
<span style="color: #000088;">$cmh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// массив заданий для мультикурла</span>
<span style="color: #000088;">$tasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// перебираем наши урлы</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// инициализируем отдельное соединение (поток)</span>
	<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// если будет редирект - перейти по нему</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_FOLLOWLOCATION<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// возвращать результат</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// не возвращать http-заголовок</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут соединения</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_CONNECTTIMEOUT<span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут ожидания</span>
	<span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_TIMEOUT<span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// добавляем дескриптор потока в массив заданий</span>
	<span style="color: #000088;">$tasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ch</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// добавляем дескриптор потока в мультикурл</span>
	<span style="color: #990000;">curl_multi_add_handle</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// количество активных потоков</span>
<span style="color: #000088;">$active</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// запускаем выполнение потоков</span>
<span style="color: #b1b100;">do</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$mrc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$active</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> 
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_CALL_MULTI_PERFORM<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// выполняем, пока есть активные потоки</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$active</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_OK<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// если какой-либо поток готов к действиям</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">curl_multi_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// ждем, пока что-нибудь изменится</span>
		<span style="color: #b1b100;">do</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$mrc</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$active</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// получаем информацию о потоке</span>
			<span style="color: #000088;">$info</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_info_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// если поток завершился</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'msg'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> CURLMSG_DONE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'handle'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору потока в массиве заданий</span>
				<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// забираем содержимое</span>
				<span style="color: #000088;">$tasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_multi_getcontent</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// удаляем поток из мультикурла</span>
				<span style="color: #990000;">curl_multi_remove_handle</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #666666; font-style: italic;">// закрываем отдельное соединение (поток)</span>
				<span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$mrc</span> <span style="color: #339933;">==</span> CURLM_CALL_MULTI_PERFORM<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// закрываем мультикурл</span>
<span style="color: #990000;">curl_multi_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Код подробно откомментирован, но давайте разберем все по порядку.<br />
В 7 строчке мы инициализируем контейнер для отдельных соединений curl (далее я буду называть его <em>мультикурл</em>), именно он позволит нам проводить операции с ними <em>параллельно</em>.<br />
Далее в цикле инициализируем соединение (назовем его <em>поток</em>) для каждого урла из нашего массива, попутно добавляя его в мультикурл и в массив заданий $tasks. $tasks – массив, в котором ключами являются адреса наших страниц, а значениями – соответствующие дескрипторы curl. <em>Функция curl_multi_add_handle</em> добавляет к дескриптору нашего мультизапросного соединения отдельное созданное соединение.</p>
<p>
В 34 строке запускается цикл для начала работы нашего мультикурла. <em>Функция curl_multi_exec</em> <strong>одновременно отправляет на выполнение все объявленные потоки</strong>, при этом в переменную $active заносится количество выполняемых потоков.
</p>
<p>
В основном цикле, начинающемся на 40 строчке, происходят главные действия. Он выполняется до тех пор, пока есть незавершенные потоки или пока не произошла ошибка. В 42 строке вызывается <em>функция curl_multi_select</em>, которая проверяет готовность какого-либо из потоков к дальнейшим действиям с ним. Затем, в 47 строке, <em>функцией curl_multi_info_read</em> получаем информацию о потоке. Но так как curl_multi_info_read обновляет возвращаемую информацию только после вызова curl_multi_exec, сделаем это в строке 45.
</p>
<p>Функция curl_multi_info_read возвращает массив, в котором нас интересуют ключи &#8216;msg&#8217; и &#8216;handle&#8217;. По &#8216;msg&#8217; мы проверяем, выполнился ли поток, а по &#8216;handle&#8217; узнаем его дескриптор. Получив дескриптор, ищем по массиву заданий, к какому урлу он относится и записываем вместо него вожделенное содержимое страницы, получаемое <em>функцией curl_multi_getcontent</em>.<br />
Теперь, когда данный поток выполнил свою задачу, удаляем его из мультикурла, а потом закрываем самого.</p>
<p>После завершения всех потоков <em>функцией curl_multi_close</em> закрываем мультикурл.</p>
<p>Сейчас в массиве заданий $tasks находятся html-коды заданных страниц.</p>
<p>Надеюсь, после прочтения статьи стало немного понятнее, как можно реализовать выполнение &#8220;многопоточных&#8221; запросов на PHP.</p>
<p>В <a href="/articles/post/92" target="_blank">следующей статье</a> рассмотрим использование stream-функций для подобных целей.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/67/feed</wfw:commentRss>
		<slash:comments>17396</slash:comments>
		</item>
		<item>
		<title>&#8220;Многопоточность&#8221; в PHP (вступление)</title>
		<link>http://job-interview.ru/articles/post/62</link>
		<comments>http://job-interview.ru/articles/post/62#comments</comments>
		<pubDate>Thu, 09 Jul 2009 07:05:07 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[многозадачность]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[многопроцессность]]></category>

		<guid isPermaLink="false">/articles/?p=62</guid>
		<description><![CDATA[Intro
Эта небольшая серия статей является обобщением материала, найденного в интернете и не претендует на оригинальность. Идея ее написать возникла у меня после поиска информации по каждому из пунктов данного материала, чтобы облегчить задачу тем, кому придется столкнуться с данной темой.

Сразу хочу сказать, что многопоточности в PHP нет. Не зря слово многопоточность в заголовке взято в [...]]]></description>
			<content:encoded><![CDATA[<h3>Intro</h3>
<p>Эта небольшая серия статей является обобщением материала, найденного в интернете и не претендует на оригинальность. Идея ее написать возникла у меня после поиска информации по каждому из пунктов данного материала, чтобы облегчить задачу тем, кому придется столкнуться с данной темой.
</p>
<p>Сразу хочу сказать, что <b>многопоточности в PHP нет</b>. Не зря слово многопоточность в заголовке взято в кавычки. Да, существует <em>многопроцессность</em>, реализующаяся средствами операционной системы (этот случай будет разобран), <em>многозадачность</em>, но <em>многопоточности</em> не существует. Однако некоторые задачи все-таки можно выполнять <em>параллельно</em>.
</p>
<p>Возьмем пример, встречающийся достаточно часто: <strong>скачать программно содержимое нескольких страниц</strong>. Если страниц немного, то их можно без проблем и больших затрат времени загрузить последовательно. Но если их тысячи? И вот здесь можно применить подходы, позволяющие <strong>выполнить скачивание одновременно</strong>. Некоторые из них и будут подробно описаны в данном материале. Сначала мы рассмотрим <a href="/articles/post/67" target="_blank">использование библиотеки curl</a>, которая может производить загрузку одновременно нескольких страниц. Затем попробуем применить к нашей задаче <a href="/articles/post/92" target="_blank">stream-функции</a>. После этого сделаем то же самое с помощью <a href="/articles/post/194" target="_blank">асинхронных сокетов</a>. И наконец распараллелим наш процесс функцией fork.</p>
<p>Все способы проверены на личном опыте. Для примеров взят максимум простой код, без оптимизации, его цель – показать принципы работы каждого метода.
</p>
<p>Для вступления рассмотрим такой способ, как</p>
<h3>Вызов одновременно нескольких копий скрипта</h3>
<p>Суть состоит в том, что <strong>один скрипт вызывается с разными параметрами</strong>, разбивающими задачу на несколько одинаковых подзадач.</p>
<p>Пример. Пусть у нас есть скрипт getcontent.php</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'rambler.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'bing.com'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'mail.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$k</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'k'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$urls</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$k</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$content</span> <span style="color: #339933;">=</span> <span style="color: #990000;">file_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$f</span> <span style="color: #339933;">=</span> <span style="color: #990000;">fopen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$k</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'.cont'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'w'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">fwrite</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$f</span><span style="color: #339933;">,</span> <span style="color: #000088;">$content</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$f</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Здесь $urls – массив урлов, содержимое с которых нам надо получить.<br />
Вызывая этот скрипт как getcontent.php?k=n , где n равен какому-либо ключу массива $urls, мы получим на жестком диске файл с именем n.cont, в котором и сохранен html интересующей нас страницы.
</p>
<p>Теперь откроем в браузере пять вкладок, напишем в адресной строке первой http://путь/getcontent.php?k=0, адресной строке второй http://путь/getcontent.php?k=1 и т.д. до http://путь/getcontent.php?k=4 и в каждой быстро нажмем Enter. Если теперь зайти в папку с нашим скриптом, то мы увидим там 5 файлов с html сайтов из масива, причем их получение произошло практически (зависит от того, как быстро жать enter) одновременно. Вот на таком нехитром примере мы показали простейший способ <em>выполнения одного задания в несколько &#8220;потоков&#8221;</em> <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
</p>
<p>Недостаток этого способа в том, что на каждый запущенный скрипт выделяется определенное количество памяти, общее количество которой в данном случае пропорционально количеству запущенных копий скрипта. Другой минус – неудобство управлением данными.</p>
<p>В <a href="/articles/post/67" target="_blank">следующей статье</a> мы попробуем для достижения нашей цели воспользоваться более гуманным способом – использовать библиотеку curl.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/62/feed</wfw:commentRss>
		<slash:comments>66</slash:comments>
		</item>
	</channel>
</rss>
