<?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; Pablo Monteagudo</title>
	<atom:link href="http://job-interview.ru/articles/post/author/pablo-monteagudo/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>Программист на фрилансе</title>
		<link>http://job-interview.ru/articles/post/332</link>
		<comments>http://job-interview.ru/articles/post/332#comments</comments>
		<pubDate>Tue, 31 May 2011 19:51:38 +0000</pubDate>
		<dc:creator>Pablo Monteagudo</dc:creator>
				<category><![CDATA[Фриланс]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[фриланс-биржи]]></category>

		<guid isPermaLink="false">/articles/?p=332</guid>
		<description><![CDATA[

В этой статье я хочу описать свой опыт работы на фрилансе.

Что за фриланс?

Может быть есть люди, которые не знают, что такое фриланс? &#8220;Freelance&#8221; буквально переводится как &#8220;внештатно&#8221;, соответственно &#8220;freelancer&#8221; — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы   ) [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/img/fl_sait_1000_rub.jpg" style="float:left;margin-right:5px;width:260px;" title="Сделаю сайт за 1000 рублей" /></p>
<p>
В этой статье я хочу описать свой опыт работы на фрилансе.
</p>
<h3>Что за фриланс?</h3>
<p>
Может быть есть люди, которые не знают, что такое <b>фриланс</b>? <i>&#8220;Freelance&#8221;</i> буквально переводится как &#8220;внештатно&#8221;, соответственно <i>&#8220;freelancer&#8221;</i> — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ) и оплату выполненной работы через интернет. Существуют специальные сайты — фриланс-биржы — на которых происходит общение заказчиков, имеющих какие-либо задания, и исполнителей, готовых эти задания выполнить.
</p>
<p><span id="more-332"></span></p>
<h3>А зачем это нужно?</h3>
<p>
Наверное каждый программист замечал, что работая постоянно, у него не хватает времени заниматься какими-то своими проектами. А различные идеи периодически приходят, и думаешь: &#8220;Вот было бы время, обязательно бы это реализовал&#8221;. Да и на работе бывают времена, что приходится заниматься неинтересными делами. Тем более в мои планы не входило всю жизнь работать &#8220;на дядю&#8221;, рано или поздно пришлось бы уходить на вольные хлеба, и во время особо скучного периода на тогдашней постоянной работе я и решил это сделать.
</p>
<p>
Для начала я решил закрепиться на <b>фриланс-биржах</b>, чтобы в случае чего всегда можно было бы заработать денег, невзирая на текущую жизненную ситуацию, был бы под рукой ноутбук и интернет. К тому же всегда есть из чего выбрать: захотел делать сайт — вперед, захотел написать скрипт — флаг в руки, надоел язык программирования — меняй, никто не запрещает.
</p>
<h3>Биржи? Биржи. Биржи&#8230;</h3>
<p>
Фриланс-бирж существует множество, как российских, так и зарубежных, в итоге я зарегистрировался на трех — <i>freelancer.com</i>, <i>free-lance.ru</i> и <i>weblancer.net</i>.
</p>
<p><img src="/img/fl_ows_f.png" style="float:left;width:200px;margin-right:3px;" /></p>
<p>
freelancer.com я выбрал, так как прочитал довольно интересную статью, описывающую прелесть работы на ней. Здесь я решил представиться веб-студией, по идее такой подход вызывает больше доверия у заказчиков, придумал &#8220;конторе&#8221; название, сделал простенький логотип, зарегистрировался и начал осматриваться.<br />
Если описать в общем, сайт представляет собой типичную фриланс-биржу &#8211; страницы разделов по возможным IT-работам, например создание сайтов &#8220;под ключ&#8221;, создание дизайнов, работа с различными CMS, написание скриптов, системное администрирование и т.д. Заказчик выбирает нужный ему раздел, создает проект, на который откликаются заинтересовавшиеся фрилансеры.
</p>
<p>
На freelancer.com ищут заказы очень много фрилансеров, среди которых немало выходцев из Азии. Качество работы большинства этих товарищей, как и знание английского языка, оставляет желать лучшего (кто не слышал про программистов-индусов <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ), но они берут ценами, иногда демпинг с их стороны вызывает даже не недоумение, а смех. Вполне реально найти &#8220;исполнителя&#8221; на сложный специфичный портал за сумму например 100$ и сроком исполнения 3 дня. И это предложение еще могут перебить!<br />
Естественно, есть и мастера своего дела, с высочайшим профессионализмом, большим опытом и умением подойти к клиенту.
</p>
<p>
К сожалению, на этом сайте мне так и не удалось получить ни одного заказа, наверное из-за окончательной переориентации на отечественный рынок. Свою роль сыграли и не очень удовлетворительный английский, и разница во времени с многими заказчиками.
</p>
<p>
Российские биржи, на которых я зарегистрировался — free-lance.ru и weblancer.net. free-lance.ru &#8211; самая известная из отечественных, держит первенство по количеству проектов и активных фрилансеров. Содержит много платных услуг, жизнь без которых затруднена, например не имея pro-аккаунта можно подавать только три заявки на понравившиеся проекты в сутки. Но таким ограничением страдают все биржи, которые я встречал. Впрочем это мне не очень мешало, с первых дней мне хотелось насладится преимуществом выбора интересных заданий. К сожалению, появлялись они не так часто, как хотелось бы, а при подаче заявки меня всегда обходили более опытные исполнители, с отзывами и более долгим временем нахождения на сайте.
</p>
<p><a href="/img/fl_dem_cust.jpg" target="_blank"><img src="/img/fl_dem_cust_sm.jpg" style="float:left;margin-right:5px;" /></a></p>
<p>
Про это стоит упомянуть подробнее. Практически все заказчики смотрят на количество отзывов, имеющихся у фрилансера, которые оставили прошлые работодатели. Хорошо выполнил работу — написали положительный, плохо, не выполнил или исчез — отритцательный. Наверное уже с 3-мя отритцательными отзывами лучше завести новый аккаунт, так же как и если первый отзыв — негативный. То же самое и с временем, прошедшим после регистрации, некоторые не доверяют людям, у которых оно меньше месяца. Сначала порой приходилось работать и <del>за еду</del> просто за отзыв.
</p>
<p>
Когда подходящий проект найден, встает задача, чтобы заказчик выбрал именно вас. Тут у каждого свой подход, кто-то просто называет цену и оставляет сообщение &#8220;пишите в личку&#8221;, кто-то строчит простыни текста, в подробностях расписывая все свои предыдущие достижения, кто-то выбирает нечто среднее. По-моему стоит писать, какие подобные задания уже приходилось выполнять и по-возможности дать понять, что понимаешь задание и чуть ли не начал его делать.
</p>
<p>
Но вот первый проект получен, наконец-то меня выбрали исполнителем! Обсудив все детали задания, пора начинать работать! Но, что все не так просто, стало понятно через пару проектов. ТЗ и детали нужно обговаривать ОЧЕНЬ подробно, выясняя все до последних мелочей, иначе дорабатывать и изменять казалось бы незначительные и неважные детали и наводить красоту по вкусу заказчика можно вечно, либо, неправильно поняв суть задания, вообще выбрать неверный путь решения задачи. Был случай, когда недели две работы потратились впустую из-за непонимания и несогласованности между мной и заказчиком, в итоге я потерял деньги, а клиент время, хорошо, что в результате разошлись мирно, без написания отритцательных отзывов друг другу.
</p>
<p>
И наконец, самый приятный момент — оплата. На всех биржах есть сервисы безопасных сделок, которые сделаны для того, чтобы ни работодатель, ни исполнитель не обманывали друг друга. Я ими не пользовался ни разу, предпочитая или доверять заказчику, получая деньги после выполнения задания, или беря предоплату. В подавляющем большинстве случаев оплата происходит с помощью вебмани или яндекс-денег.
</p>
<h3>Не биржей единой</h3>
<p>
Поиск заказов не ограничивается только биржами.<br />
У многих заказчиков постоянно появляются новые задания, и если ты хорошо выполнил одно, наверняка следующее также достанется тебе, плюс этот заказчик будет рекомендовать тебя своим знакомым, у которых возникла необходимость в привлечении стороннего сотрудника.<br />
Постепенно знакомые и бывшие коллеги узнают о твоей работе на фрилансе и заказы начинают приходить через них.<br />
Через некоторое время я перестал заходить на биржи и выполнял только подобные задания, потому что они скорее всего будут интересные, с заказчиком уже сложились более-менее неплохие отношения, почти нет недоверия и настороженности, как у тебя, что прокатят с деньгами, так и у него, что работа не будет выполнена.
</p>
<p>
Также не стоит забывать про свои задумки, отводить какое-то время на них, даже если пока ни одна из них еще не приносит какой-либо ощутимой отдачи, ведь это только пока <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Главное, что для них находится время.
</p>
<h3>Ожидания и реальность</h3>
<p><img src="/img/fl_good_bad.jpg" /></p>
<p>
Для кого-то работать дома в кайф, но я знал, что постоянно находиться в четырех стенах мне будет затруднительно, однако утешал себя мыслью, что можно будет выйти, например, в парк и работать там. Но на практике зарядки ноутбука хватает не намного времени, у нетбука маленький экран, а на лавке в парке с этими девайсами неудобно сидеть. Если еще вспомнить, каким жарким было лето 2010, то можно понять, как я завидовал людям, сидящим в прохладных офисах с кондиционерами, тогда как дома был только плохо спасающий от этого ада вентилятор.
</p>
<p>
Когда я начинал свой путь по дороге фриланса, то не строил иллюзий, что в первый же день клиенты выстроятся в очередь, но все же было неожиданно, что уцепиться за первый проект удалось только недели через две. Эта ситуация получилась и из-за того, что, как упоминалось ранее, я не откликался на неинтересные заявки, а ждал чего-то более привлекательного. Зато проект оказался интересным, довольно денежным и с хорошим заказчиком, которому впоследствии я выполнил еще несколько заданий.
</p>
<p>
По поводу рабочего времени происходило примерно так, как я и думал: то работы нет, то работать приходится по ночам, не говоря уже про выходные. Если на постоянной работе знаешь, что в субботу-воскресенье отдыхаешь, на фрилансе все смешивается и иногда удивляешься радости друзей о том, что завтра выходной.<br />
Можно безболезненно с утра покататься на велосипеде, посреди рабочего дня прерваться, например, на гантели или прогулку (это если нет срочной работы, конечно <img src='/articles/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  ).
</p>
<p>
Волнующий денежный вопрос. Честно говоря, когда я уходил на фриланс, то ожидал, что буду зарабатывать больше. Очень сложно назвать среднюю сумму заработка, в первые месяцы у меня выходило не более 10-15 тысяч ежемесячно.
</p>
<h3>Итого</h3>
<p>
Что же в итоге? Не жалею ли я о том, что ушел с постоянной работы на фриланс? Нет.<br />
Сейчас я частично (5 часов в день) работаю в офисе на постоянной работе, которая нашла меня через фриланс, остальное время практически полностью посвящаю своим делам, лишь иногда откликаясь на работу от постоянных заказчиков, приобретенных на фрилансе.
</p>
<p></p>
<p>
В заключение хочу выразить огромную благодарность своей девушке Саше, которая была со мной и  поддерживала меня все это время.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/332/feed</wfw:commentRss>
		<slash:comments>298</slash:comments>
		</item>
		<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>Pablo Monteagudo</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>13232</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>Pablo Monteagudo</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>Pablo Monteagudo</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>18573</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>Pablo Monteagudo</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>
