<?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; vlubch</title>
	<atom:link href="http://software.intel.com/ru-ru/blogs/author/vlubch/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/ru-ru/blogs</link>
	<description></description>
	<lastBuildDate>Thu, 24 May 2012 12:16:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Безъядерный параллелизм</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/11/30/2006183/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/11/30/2006183/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 10:13:25 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[Разработка софта]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/11/30/2006183/</guid>
		<description><![CDATA[<p>Говорят – «голь на выдумки хитра». Можно привести и другие поговорки, суть которых в том, что обстоятельства или что-то иное «принуждают» действовать, если не необычно, то нестандартно. Иногда это может быть даже просто демонстрация иного подхода. Причины могут быть разные, но результат один – решение, демонстрирующее иные подходы, и иное, может быть, даже в чем-то парадоксальное мышление. </p>
<p>Возьмем известные всем прерывания. Кажется, без них немыслима архитектура современных процессов. И есть ли вообще такие, в которых не реализованы принципы аппаратного прерывания? Как ни странным может показаться, но их наличие не является столь уж обязательным. Безусловно, они  удобны и выгодны с многих позиций, но и их отсутствие не является фатальным. Но это в том случае, если в системе реализован параллелизм. Тогда обработка, реализуемая режимом прерываний, легко замещается множеством параллельных процессов.  </p>]]></description>
			<content:encoded><![CDATA[<p>Говорят – «голь на выдумки хитра». Можно привести и другие поговорки, суть которых в том, что обстоятельства или что-то иное «принуждают» действовать, если не необычно, то нестандартно. Иногда это может быть даже просто демонстрация иного подхода. Причины могут быть разные, но результат один – решение, демонстрирующее иные подходы, и иное, может быть, даже в чем-то парадоксальное мышление. </p>
<p>Возьмем известные всем прерывания. Кажется, без них немыслима архитектура современных процессов. И есть ли вообще такие, в которых не реализованы принципы аппаратного прерывания? Как ни странным может показаться, но их наличие не является столь уж обязательным. Безусловно, они  удобны и выгодны с многих позиций, но и их отсутствие не является фатальным. Но это в том случае, если в системе реализован параллелизм. Тогда обработка, реализуемая режимом прерываний, легко замещается множеством параллельных процессов.  </p>
<p>Например, известно, что ввод символов с клавиатуры выполняется в режиме, когда при нажатии какой-либо клавиши возникает аппаратное прерывание и запускается программный код, помещающий символ в некий буфер символов.  Но прерывание можно заменить параллельным процессом, отслеживающим состояние клавиатуры, который по аналогии с первым будет формировать все тот же буфер входных символов.</p>
<p>Итак, прерывания можно реализовать через параллелизм. А чем или как можно заменить параллелизм? Последний, кстати, во многом завязан на прерывания, а потому без них кажется просто немыслимым. Неужели сказанное выше фантастика, а мы имеем замкнутый круг? Ведь, когда  параллелизм основан на прерываниях, то, следовательно, мы не можем их заменить параллелизмом, поскольку последний базируется на прерываниях и так … «по кругу»?</p>
<p>Сопрограммы – это механизм, позволяющий реализовать или, что точнее, смоделировать, параллелизм без прерываний. Кстати, прерывания – это тоже моделирование параллелизма. Но мало кому понравится  самому «разбрасывать» по программному коду сопрограммные вызовы. Т.к. то, что видится достаточно простым и очевидным в случае двух параллельных программ, представляется достаточно запутанным и в большой степени малонадежно и небезопасно  в случае большего их числа.</p>
<p>С другой стороны, механизм сообщений системы Windows, являясь, по сути, реализацией сопрограммного механизма, работает достаточно надежно и вызывает нарекания лишь в случае  зацикливания  кода в рамках обработки того или иного сообщения. Если же каким-то образом гарантировать код обработчика сообщения от зацикливания и обеспечивать приемлемое время его работы (слишком большое время обработки сообщения ведет к задержке обработки других сообщений), то реализация параллелизма через механизм обработки сообщений представляет такую же альтернативу стандартному механизму реализации параллелизма, как и сопрограммы.</p>
<p>А в чем же отличие многопоточного программирования от многоядерного? Только в одном – в самом подходе к реализации параллелизма. Если в первом случае он моделируется, то во втором - реализуется  физически. Подчеркнем, что именно реализуется, а не моделируется.  </p>
<p>Но поскольку числа ядер, какое бы [разумное] число их ни было, явно недостаточно, то не представляется возможным отказать от моделирования параллелизма, используя идею многопоточности. В результате программист часто пишет программу в рамках все той же парадигмы, а уже планирование потоков на физические ядра реализуется неявными  или даже скрытыми от него механизмами.</p>
<p>Итак, многопоточность – forever?! И да и нет. Да, как механизм реализации параллелизма для так называемых слабосвязанных и/или крупноблочных параллельных процессов.  Но такие параллельные процессы можно назвать параллельными лишь весьма условно. В теории параллельных процессов процессы, хотя физически и работающие параллельно, но не связанные между собой каким-либо взаимодействием, не считаются параллельным.  И даже наличие «слабого» взаимодействия в этом смысле мало меняет их суть.    </p>
<p>Многопоточности, а соответственно и многоядерности, необходимо сказать нет, если речь идет о параллельных вычислениях. Во-первых, потому, что многопоточность – это лишь структурный механизм моделирования параллельной работы процессов, но никак не модель параллельных вычислений. Во-вторых, поточный механизм абсолютно неэффективен в случае сильносвязанных процессов и, тем более, мелкоблочных параллельных процессов, когда размер параллельного блока определяется буквально одной или несколькими командами.   </p>
<p>О том, чем можно заменить многопоточный параллелизм, демонстрирует технология Визуально-Кубического Программирования (автоматного) – ВКП(а). В ее рамках программист оперирует автоматной моделью параллельных процессов и никак не ограничен размерами непрерываемой единицы программного кода (в терминологии потоков). Кроме того, формулировка любых алгоритмов в рамках параллельной модели вычислений позволяет избежать множества проблем, присущих многопоточным вычислениям, связанным с синхронизацией, гонками, блокировками, общим доступом к данным и т.д. и т.п. Но о принципах, механизмах, деталях реализации ВКП(а), о ее базовой вычислительной модели  мы поговорим отдельно (такой разговор частично уже начат, см., например, об автоматной модели вычислений  - <a href="http://software.intel.com/ru-ru/blogs/2010/03/05/2003255/">software.intel.com/ru-ru/blogs/2010/03/05/2003255/</a>).</p>
<p>P.S.<br />
Название статьи отнюдь не означает причисление автора к противникам многопоточности, а тем паче - многоядерных процессоров. И то и другое – лучше, чем ничего. Но то, что архитектура процессора должна соответствовать [уж хоть какой-либо!] параллельной модели вычислений,  не должно вызывать, если не сомнений, то хотя бы сознания необходимости этого. Время назрело: стремление параллельно программировать входит в противоречие с устаревшей моделью и архитектурой вычислений. Все это, даже при увеличении числа ядер, пока остается прежним - последовательным. </p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/11/30/2006183/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Королевство кривых зеркал</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/09/20/2005201/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/09/20/2005201/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 06:09:21 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[Разработка софта]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/09/20/2005201/</guid>
		<description><![CDATA[Уже давно поведение некоторого программного объекта, можно представить процессом, представленным такими понятиями, как поток, нить и т.п. Используя подобные «программные отражения», можно судить о поведении не только одного, но и множества объектов/процессов.  А если при этом важна скорость вычислений, то множество процессов можно отобразить на множество реальных процессоров или в современном понимании – множество процессорных ядер в многоядерном процессоре. Такой подход к параллелизму остается неизменным уже многие годы и, более того, предлагается в качестве базы и для его дальнейшего развития.</br>

Но… как быть с то там, то здесь явно проявляющейся «кривизной» параллельного программирования? Когда программист не может, не знает или имеет проблемы с синхронизацией работы множества объектов, то они превращаются в некую неуправляемую массу.]]></description>
			<content:encoded><![CDATA[<p>Приятно, когда квадратное -  квадратно, а круглое – кругло.. Программирование подобно зеркалу, только предназначенному в большей степени отражать поведение объектов, чем их внешний вид. Хотя бы потому, что убогое поведение программы может легко «убить» преимущества самой привлекательной и изощренной графики.</p>
<p>Пожалуй, именно несоответствие отражения реального мира в последовательном программировании постепенно привело к нынешней повальной заинтересованности программированием параллельным.  Кто-то может возразить, что всему причиной кризис производительности процессоров? Да – и это, но скорость лишь одна причина и далеко не основная, т.к. гораздо больше проблем доставляет все большая сложность решаемых задач. При этом адекватное и правильное отражение поведения программных объектов много важнее утилитарной скорости их просчета. Ну, какой толк от «быстрого» калькулятора, но выдающего неверный результат?</p>
<p>Уже давно поведение некоторого программного объекта, можно представить процессом, представленным такими понятиями, как поток, нить и т.п. Используя подобные «программные отражения», можно судить о поведении не только одного, но и множества объектов/процессов.  А если при этом важна скорость вычислений, то множество процессов можно отобразить на множество реальных процессоров или в современном понимании – множество процессорных ядер в многоядерном процессоре. Такой подход к параллелизму остается неизменным уже многие годы и, более того, предлагается в качестве базы и для его дальнейшего развития.</p>
<p>Но… как быть с то там, то здесь явно проявляющейся «кривизной» параллельного программирования? Когда программист не может, не знает или имеет проблемы с синхронизацией работы множества объектов, то они превращаются в некую неуправляемую массу.</p>
<p>Покажем, как в параллельном программировании буквально на пустом месте создаются проблемы. Рассмотрим следующую простейшую систему из двух уравнений:</p>
<blockquote><p>
       a = a + 1;<br />
       b = b + 1;
</p></blockquote>
<p>Условно можно принять, что переменные a и b будут отражать в данном случае число «шагов» программных процессов, где «шаг» - элементарная операция увеличения переменной на единицу. Для так называемых несвязанных процессов (процессов, не имеющих общих переменных), мы каких-то проблем не испытываем – шагают и шагают... Но, если через какое-то время, вы их остановите одновременно, то может случиться, что даже с одинаковыми исходными данными, они, запущенные одновременно, могут выдать разный результат.</p>
<p>Но еще интереснее - взаимосвязанные процессы. Немного усложним нашу систему уравнений, рассмотрев следующую систему:</p>
<blockquote><p>
       c = a + b;<br />
       b = c + d;
</p></blockquote>
<p>По сравнению с первым уравнением здесь увеличено число переменных, а некоторые из них являются еще и общими. Собственно последние и представляют связи между процессами.</p>
<p>Любой легко может убедиться, просчитав хотя бы «на пальцах», что при начальных значениях переменных a = b = 1, c = d = 0 через пять дискретных тактов/шагов должно быть b=2, c= 4. Но, как это ни поразительно, написанная «в лоб» современная параллельная программа может выдать иной результат (один из вариантов - 6, 6). А все потому, что в той же многопоточной среде, результат будет зависеть от моментов доступа процессов к общим переменным в пределах текущего дискретного такта времени.</p>
<p>Выше мы рассмотрели столь простые и столь очевидные факты, что их наличие представляется, если не бредом, то какой-то загадкой параллельного программирования. И она есть! И разгадка данной загадки требует иного взгляда на саму программную модель вычислений, процесс программирования и архитектуру процессоров. Т.е. вместо того, чтобы раз от разу стоически преодолевать последствия той или иной «кривизны», необходимо совершенствовать параллельную программную модель. Это позволит решить некоторые проблемы раз и навсегда.</p>
<p>Сказанное не является таким уж откровением. Просто подобные факты или затушевываются или не очень серьезно воспринимаются. Сталкиваясь с подобными проблемами в том или ином их проявлении, программисты искали и находили свои методы и подходы к их решению. Так, понятие дискретного времени и определенные режимы и/или ограничения на работу с данными используются в системах программирования контроллеров, компьютерного моделирования и визуально-ориентированного блочного имитационного моделирования динамических систем и т.д. и т.п.  Но проблема в том, что где-то учтено одно, где-то другое, а что-то упущено совсем.  А все потому, что как не было, так и нет ни единого взгляда на параллельные вычисления ни общего решения данных проблем.</p>
<p>Главное, чтобы программисты не считали себя первопроходцами и не игнорировали опыт тех, кто проблемы параллелизма начал решать гораздо раньше. И добился на этом поприще определенных успехов. Например, те же разработчики «железа». Множество параллельно работающих элементов в схемах, гонки сигналов, разрешение всевозможных конфликтов, дискретные модели, теория анализа и синтеза цифровых схем и т.д. и т.п. – все это для них уже давно сложившиеся понятия. Современные успехи в проектировании процессоров – это одновременно и результат успешного решения проблем параллелизма, который имеет общие корни вне зависимости от  своей реализации - программной ли или аппаратной.</p>
<p>А в какое «зеркало» вы, параллельные программисты, смотритесь и что делаете, заметив искажение «изображения»? Меняете его, стучите по нему или обреченно пользуетесь тем, что есть? Или вы попросту далеки от рассмотренных только что проблем? Но занимаетесь ли вы тогда вообще параллельным программированием?</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/09/20/2005201/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Игры ума или о теории параллельных процессов</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/03/05/2003255/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/03/05/2003255/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 19:58:02 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Параллельное программирование]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/03/05/2003255/</guid>
		<description><![CDATA[В блоге «<a href="http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/">Почему асинхронные системы не могут быть быстрее синхронных, а их программирование намного сложнее</a>» была упомянута задача Майхилла. Синхронное ее решение известно, а вот с асинхронным – проблема. И не заметно, чтобы кто-то приступил не то, чтобы к реализации, но хотя бы просто к обсуждению тех проблем, в которые целятся стрелки. Два комментария на блок, из которых один авторский, маловато. Неужели все проблемы параллелизма «расстреляны»?]]></description>
			<content:encoded><![CDATA[<p>В блоге «<a href="http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/">Почему асинхронные системы не могут быть быстрее синхронных, а их программирование намного сложнее</a>» была упомянута задача Майхилла. Синхронное ее решение известно, а вот с асинхронным – проблема. И не заметно, чтобы кто-то приступил не то, чтобы к реализации, но хотя бы просто к обсуждению тех проблем, в которые целятся стрелки. Два комментария на блок, из которых один авторский, маловато. Неужели все проблемы параллелизма «расстреляны»?</p>
<p>Мы пока не будем реализовывать асинхронное решение для стрелков, рассмотренное Варшавским и Поспеловым в [1]. Лично мне ясно и без реализации - и возни будет больше и быстрее они не станут. Это же нас ожидает и в любом другом асинхронном случае. Собственно этой проблеме и был посвящен упомянутый блог. Но есть, ведь, и иное мнение? Мои же выводы – это мой опыт. Т.е. у меня по-другому что-то не получалось, да и у других я видел то же самое. Сравните хотя бы синхронное (Трахтенброт) и асинхронное (Варшавский, Поспелов) решения задачи Майхилла. А уж когда есть простое решение, то усложнять себе жизнь не очень и хочется, правда ли? Тут нужен стимул. Хоть какой-нибудь.</p>
<p>… А что-то точит – сделай, сделай! «Покажи, докажи, если уж остальным слабо» - говорит «первое я». «А зачем?» – возражает ему «второе»? – «Ведь, и так все ясно!» «Так, неужели, слабо?» – опять нудит «первое»! «А стимул?» – «второе»… Но вот «первое» начинает понемногу бороть «второе», т.к. … появляется вариант: асинхронный алгоритм оставим на потом, а попробуем распараллелить уже имеющийся синхронный. Тем более, что он, если присмотреться, похож на асинхронный, т.к. сигнал «огонь» распространяется подобно сигналу «а1» (см.[1]), а потом он же отраженный, но имеющий имя «готов», бежит обратно. Мысль следующая – преобразуем в параллельную форму синхронный вариант, а там, может, дело дойдет и до асинхронного, но с несколькими сигналами. Более того, есть теория, которая позволит решить проблему распараллеливания, не очень-то напрягая серое вещество. А проверка и демонстрация возможностей подобной теории – чем не стимул? Ну, а уж дальше – только ввяжись!</p>
<p>Итак, приступим! Синхронное решение, автоматный граф которого известен (см. [2]), в аналитической форме можно описать так. Пусть дан автомат M = (X, Q, Y, sleep, F(x/y)), где  X = {x1, x2}, Y = {y1, y2}, Q = {sleep, fire, ready, shot}, q0 = sleep, где отображение F определяется следующим образом:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
F sleep =  {fire(x1/y1)},
F fire 	=  {ready(x2/-)},
F ready =  {shot(-/y2)},
F shot 	=  {sleep(-/-)}.</pre>
<p>Функциональное назначение предикатов и действий следующее (см. также [2]):<br />
// предикаты<br />
x1) внутреннее состояние соседа слева «fire»?<br />
x2) внутреннее состояние соседа справа «ready»?<br />
// действия<br />
y1) установить свой номер n равный на единицу больше, чем номер соседа слева.<br />
y2) выполнить задержку на n-1 дискретных тактов.</p>
<p><img class="alignleft size-full wp-image-2003264" title="fig1" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/fig11.jpg" alt="" width="227" height="203" />Граф автомата M показан на рис.1. Он несколько отличается от приведенного в статье [2]. Мы заменили подсчет числа тактов на вызов вложенного автомата, реализующего задержку на нужное число дискретных тактов. Так, во-первых, демонстрируется прием, аналогичный подпрограммам, а, во-вторых, и само решение в этом случае проще.<br />
Автомат M можно разложить на некоторое число параллельных автоматов, которые своими состояниями и переходами покроют его множество состояний и переходов. Поскольку он имеет четыре состояния, то для этого достаточно двух автоматов по два состояния.</p>
<p>Пусть это будут автоматы S = (X1, Q1, Y1, s0, F1(x, y)), где Q1 = {s0, s1} и A = (X2, Q2, Y2, a0, F2(x, y)), где Q2 = {a0, a1}.<br />
Закодируем состояния автомата M состояниями автоматов S и A. Пусть sleep = s0a0, fire = s0a1, ready = s1a0, shot = s1a1. После этого, применив к автомату M операцию декомпозиции – деления автоматов (подробно об алгебраических операциях над автоматами см. в [3]), мы получим параллельную модель из двух автоматов, где M = S||A, аналитическая форма которых будет следующей. Автомат S = (X1, Q1, Y1, s0, F1(x, y)), где X1={x2, a2}, Y1={-}, Q1={s0, s1}, где функция переходов F1:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
s0 = {s1(x2a1/-)},
s1 = {s0(a1/-)}.
</pre>
<p>Автомат A = (X2, Q2, Y2, a0, F2(x, y)), где X2={x1, s0}, Y2={y1, y2}, Q1={a0, a1}, где функция переходов F2:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
a0 = {a1(x1s0/y1), a1(s1/y2)},
a1 = {a0(x2/-), a0(s1/-)}.
</pre>
<p>В дальнейшем мы чаще будем использовать упрощенную запись вида M = S||A, где:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
S:
s0 = {s1(x2a1/-)},
s1 = {s0(a1/-)}.
A:
a0 = {a1(x1s0/y1), a1(s1/y2)},
a1 = {a0(x2/-), a0(s1/-)}.
</pre>
<p>В параллельной автоматной модели внутренние состояния используются для синхронизации, а потому в автомате удобно заменить имена предикатов: у автомата, например S на имена состояний автомата - A, с которым он синхронизирует свою работу, и наоборот.</p>
<p>Применимая на практике теория параллельных процессов, - что еще надо для хорошей жизни? Теперь, если мы реализуем исходную модель – она уже есть - и эквивалентную ей параллельную – ее создадим по аналогии - и выведем протокол работы, фиксирующий на каждом дискретном шаге состояния автоматов, то получим идентичные протоколы. Например, для пяти стрелков они будут иметь следующий вид (первый объект – офицер, отдающий команду «огонь» - fire):</p>
<pre name="code" class="plain:nogutter:nocontrols:">
1:fire,fire,sleep,sleep,sleep,sleep,
2:wait,fire,fire,sleep,sleep,sleep,
3:wait,fire,fire,fire,sleep,sleep,
4:wait,fire,fire,fire,fire,sleep,
5:wait,fire,fire,fire,fire,fire,
6:wait,fire,fire,fire,fire,ready,
7:wait,fire,fire,fire,ready,ready,
8:wait,fire,fire,ready,ready,ready,
9:wait,fire,ready,ready,ready,ready,
10:wait,ready,ready,ready,ready,ready,
11:wait,shot,shot,shot,shot,shot,
12:wait,sleep,sleep,sleep,sleep,sleep,
</pre>
<p><i>Листинг 1. Протокол функционирования цепи из 5-ти стрелков и офицера</i></p>
<p>И это все?! В принципе да. Поставленную цель – распараллелить алгоритм мы достигли. Для этого 1) сформулировали решение, 2) создали его модель в форме автомата, 3) используя алгебру автоматов, распараллелили. Хорошо? Хорошо! Есть практическая польза? Есть! Хотя, если смотреть на одинаковые протоколы работы моделей, то, что последовательное решение, что параллельное – все едино?! Разница, конечно, есть, но тут надо заглядывать уже вовнутрь. Это сделаем как-нибудь в другой раз. Сейчас же посмотрим на нашу параллельную модель с другой точки зрения.</p>
<p>Выше мы решили задачу так называемого автоматического распараллеливания. Пользы от нее, как можно предположить, не так чтобы уж много, но есть (так, порой, мы себя утешаем). А вот с какими проблемами мы можем столкнуться, создавая самостоятельно параллельное решение? Покажем это на примере рассмотренной выше параллельной модели. Представим, что мы ее создали «ручками», но ошиблись, упустив одну синхронизирующую связь. Или другими словами есть следующая модель M1=S||A, где:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
S:
s0 = {s1(x2a1/-},
s1 = {s0(a1/-}.
A:
a0 = {a1(x1/y1), a1(s1/y2)},
a1 = {a0(x2/-), a0(s1/-)}.
</pre>
<p>Разницу между моделями M и M1 на первый взгляд уловить даже сложно. Но подскажем – отличаются строки, соответствующие состоянию a0 отображения автомата A. Еще точнее – первый элемент во множестве его переходов. Допущенная ошибка приводит к следующему протоколу:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
1:fire,fire,sleep,sleep,sleep,sleep,
2:wait,fire,fire,sleep,sleep,sleep,
3:wait,fire,fire,fire,sleep,sleep,
4:wait,fire,fire,fire,fire,sleep,
5:wait,fire,fire,fire,fire,fire,
6:wait,fire,fire,fire,fire,ready,
7:wait,fire,fire,fire,ready,shot,
8:wait,fire,fire,ready,shot,sleep,
9:wait,fire,ready,shot,sleep,sleep,
10:wait,ready,shot,sleep,sleep,sleep,
11:wait,shot,sleep,sleep,sleep,sleep,
12:wait,sleep,sleep,sleep,sleep,sleep,
</pre>
<p><i>Листинг 2. Протокол работы стрелков с одной удаленной связью</i></p>
<p>Всего-то одна связь, а разлад полный! Почему? Ответ узнаем, если построим эквивалентную параллельной модели однокомпонентную модель. Для этого применим к автоматам S и A операцию композиции – умножения автоматов. В результате мы получим автомат M1=( X3, Q3, Y3, a0s0, F3(x, y)), у которого функция переходов будет следующей:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
F3s0a0 =  {s0a1(x1^x2/y1), s1a0(^x1x2/-), s1a1(x1x2/-)},
F3s0a1 =  {s1a0(x2/-)},
F3s1a0 =  {s1a1(x1/y1), s1a1(-/y2)},
F3s1a1 =  { s0a0(-/-)}.
</pre>
<p>Перекодировав состояния (см. кодировку выше), получим:</p>
<pre name="code" class="plain:nogutter:nocontrols:">
F3:
F3sleep =  {fire(x1^x2/y1), ready(^x1x2/-), shot(x1x2/-)},
F3fire =  {ready(x2/-)},
F3ready =  {shot(x1/y1), shot(-/y2)},
F3shot =  {sleep(-/-)}.
</pre>
<p><img class="alignleft size-full wp-image-2003265" title="fig2" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/fig2.jpg" alt="" width="227" height="210" />Граф автомата M1 показан на рис. 2. Источником замеченной ошибки являются переходы из состояния ready (см. листинг 2). Во-первых, они некорректны, т.к. нарушается условие ортогональности переходов автоматной модели. Мы могли бы не доводить дело до реализации «ошибочной модели», а уже на этапе формального анализа, выявив подобную грубейшую ошибку, принять немедленные меры к ее устранению.  Это ли не стимул или не мечта – выявлять ошибки на начальном этапе проектирования?! Только за это теории параллельных процессов нужно кланяться в ножки!</p>
<p>Итак, вначале мы поставили весьма глобальные вопросы, а затем дали на них вполне конкретные ответы. Мы, правда, не расписали алгоритмы самих операций над автоматами, но, во-первых, такой цели не было, во-вторых, это значительно увеличило бы объем статьи, в-третьих, требует определенных знаний, а, в-четвертых, многие ли задумываются над алгоритмами тех же обычных арифметических операций, применяя их. Главное, что они есть и им можно доверять. Так и здесь: есть автоматная модель параллельных процессов и ее математика – алгебра автоматов. Ну и, безусловно, архиважно, что все это не так уж сложно и практически применимо.</p>
<p>Подводя итог, можно утверждать, что, не имея подобной модели и подобного математического инструментария, не владея им, мы были, будем и останемся пещерными программистами[4]. Особенно в области параллельного программирования, да и собственно аппаратных архитектур. Не стремится к этому – грош цена нашим мечтам и разговорам об инновациях, модернизации и т.д. и т.п.</p>
<p>Без теории – плохо, но и теория, которую сложно или невозможно применить на практике, имеет мало смысла. В рамках автоматной модели параллельных вычислений, как можно видеть, одно сочетается с другим, т.е. (похвалим сами себя, коль пока никто на это не решается (см. также упомянутый <a href="http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/">блог</a>), за проделанную работу) все не только хорошо, но и практически полезно! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Литература<br />
1.	Варшавский В.И., Поспелов Д.А. Оркестр играет без дирижера: размышления об эволюции некоторых технических систем и управления ими. - М.: Наука. Главная редакция физико-математической литературы, 1984, - 208с.<br />
2.	Любченко В.С. Батарея огонь! или Задача Майхилла для Microsoft Visual C++ (О синхронизации процессов в среде Windows). «Мир ПК», № 2/00. <a href="http://www.osp.ru/pcworld/2000/02/154727/">http://www.osp.ru/pcworld/2000/02/154727/</a><br />
3.	Мелихов А.Н. Ориентированные графы и конечные автоматы. – М.: Наука, 1971. – 416 с.<br />
4.	Любченко В.С. Пещерное программирование. “Открытые системы”, #5/2009, <a href="http://www.osp.ru/os/2009/05/9864607/">http://www.osp.ru/os/2009/05/9864607/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/03/05/2003255/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Почему асинхронные системы не могут быть быстрее синхронных, а их программирование намного сложнее</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 14:48:09 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Академическое сообщество]]></category>
		<category><![CDATA[Параллельное программирование]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/</guid>
		<description><![CDATA[«Лобовые» методы повышения быстродействия фактически исчерпаны. А поэтому нет-нет, да и вновь вспоминают об асинхронных принципах работы. Считается, что уж они-то в общем случае должно быть быстрее. Но почему, несмотря на давнюю свою известность и наличие практических решений и теории, асинхронные схемы так и не получили широкого распространения, остановившись в своем развитии по сути на [...]]]></description>
			<content:encoded><![CDATA[<p>«Лобовые» методы повышения быстродействия фактически исчерпаны. А поэтому нет-нет,  да и вновь вспоминают об асинхронных принципах работы. Считается, что уж они-то в общем случае должно быть быстрее. Но почему, несмотря на давнюю свою известность и наличие практических решений и теории, асинхронные схемы так и не получили широкого распространения, остановившись в своем развитии по сути на экспериментальном уровне?</p>
<p>Асинхронная схемотехника не оправдывает возлагаемых на нее надежд, т.к. подобное решение будет скорее медленнее, а его проектирование может быть на порядки сложнее в сравнении с аналогичным синхронным решением. И это не является новостью, т.к. уже в одной из первых книг по асинхронным системам -  «Апериодические автоматы»  под ред. В.И. Варшавского сказано, что в асинхронных схемах «мы подчас получаем даже меньшие скорости работы, чем в синхронных».  И с этим можно было бы даже мириться, если бы само проектирование асинхронных систем было проще! Но и это, к сожалению, не так.</p>
<p>Но, может, сказанное относится только к аппаратным решениям, а в случае программ работают иные законы? То, что с программами не лучше, чем со схемами, можно убедиться, сравнивая между собой программы, созданные на асинхронных принципах, с эквивалентными им синхронными программами.  В статье  «Параллельные сортировки: быстрее, проще... умнее» показано не только, что параллельное решения должно быть быстрее последовательного, но и то, что синхронное решение может быть в разы быстрее  асинхронного  (см. <a href="http://www.osp.ru/os/2004/05/184293/">www.osp.ru/os/2004/05/184293/</a>).</p>
<p>Скорость работы параллельной системы во много определяется сложностью протоколов взаимодействия параллельных компонентов. У синхронных систем они проще. Параллельные сортировки это демонстрируют достаточно убедительно. Так синхронная конвейерная сортировка - Pipeline  более чем в пять раз быстрее асинхронной параллельной Ф-сортировки - Philosopher (см.  колонку I табл. 2 упомянутой выше статьи).</p>
<p>Можно рассмотреть и другую параллельную задачу – задачу Майхилла для цепи стрелков. Ее решение также возможно как в синхронном, так и асинхронном варианте. И здесь наблюдается тот же эффект - синхронное решение проще. Он представлен в статье «Батарея  огонь! Или задача Майхилла для Microsoft  Visual C++» (см. <a href="http://www.osp.ru/pcworld/2000/02/154727/">www.osp.ru/pcworld/2000/02/154727/</a>). Варианты асинхронного взаимодействия стрелков - в главе 5 книги Варшавский В.И., Поспелов Д.А. Оркестр играет без дирижера: размышления об эволюции некоторых технических систем и управлении ими (скачать электронный вариант книги можно по ссылке: <a href="http://www.mirknig.com/knigi/1181176954-orkestr-igraet-bez-dirizhera-razmyshleniya-ob.html">www.mirknig.com/knigi/1181176954-orkestr-igraet-bez-dirizhera-razmyshleniya-ob.html</a>).</p>
<p>Эти факты не могут не убеждать, что асинхронное решение, как правило, сложнее и, порой, намного сложнее соответствующего синхронного (в первую очередь, конечно, имеется в виду сложность взаимодействия параллельных асинхронных процессов), а потому и, как следствие такой сложности, медленнее. Современные многоядерные системы и многопоточное программирование – это по своей сути асинхронные решения, а потому приведенные примеры не могут не наталкивать на определенные выводы и размышления.</p>
<p>Может именно в силу рассмотренных причин современное параллельное программирование столь сложно, не надежно и не оправдывает надежд, связанных с повышением скорости работы программ? Но если кто-то думает иначе, то пусть … решит задачу Майхилла хотя бы в одном из асинхронных вариантов (см. книгу Варшавского В.И. и Поспелова Д.А.).</p>
<p>Сказанное выше не означает, что автор противник асинхронных вычислений. Есть случаи, когда без них, «как без воды». Но зачем «огород городить», когда все, так сказать, в пределах прямой видимости и/или слышимости? Уж «стрелкам», думаю, это  понятно.  Хотя есть случаи, когда между ними нужно протянуть и «веревочку». Но их гораздо меньше, чем это может показаться, глядя на принципы работы современных параллельных систем и соответствующего программного обеспечения.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/02/17/2003103/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>О настоящем и мнимом или … вопрос к Деду Морозу?</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/12/28/2002872/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/12/28/2002872/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 10:43:18 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/12/28/2002872/</guid>
		<description><![CDATA[Как отличить то, что им является, от того, что им лишь называется?… Пример первый. В обычном [одноядерном] процессоре параллельно функционирующих узлов достаточное количество, но это не повод считать его параллельным? Но почему мы должны его считать таким, если на одном чипе разместить несколько ядер? Ведь, сколько ни собирай в одном месте машин, они в самолет [...]]]></description>
			<content:encoded><![CDATA[<p><strong><em>Как отличить то, что им является, от того, что им лишь называется?…</em></strong><br />
<strong>Пример первый.</strong> В обычном [одноядерном] процессоре параллельно функционирующих узлов достаточное количество, но это не повод считать его параллельным? Но почему мы должны его считать таким, если на одном чипе разместить несколько ядер? Ведь, сколько ни собирай в одном месте машин, они в самолет не превратятся!?<br />
<strong>Пример второй.</strong> Перед вами «черный ящик» с «ручкой скорости». Снимем его характеристику - вычислительную сложность, определяющую зависимость во времени получения результата от входных данных. Пусть ее график имеет экспоненциальную форму. Если мы будем крутить ручку, то график будет сжиматься по оси времени при увеличении скорости и, наоборот, растягиваться при уменьшении. Но сам вид графика при этом будет неизменным. Следовательно, именно вид графика отражает свойства «ящика». Так разгоняют процессоры. Но разогнанный процессор – не новый процессор.  Если что при этом существенно меняется, то, прежде всего, надежность его работы.<br />
<strong>Пример третий.</strong> Все тот же «ящик». Не заглядывая в него, может ли  кто-то дать ответ о его устройстве? Реализован он на жесткой логике, или «мягком» софте? Он параллельный или последовательный? На первый взгляд ответить на это проще, чем на тест Тьюринга, но и тут распознать «Кто есть Кто» без дополнительной информации вряд ли возможно.<br />
<strong><em>Следствие.</em></strong> 1) Любой алгоритм может быть реализован как аппаратно, так и программно. 2) Для любого параллельного алгоритма есть эквивалентный последовательный и наоборот.<br />
<strong><em>Следствие следствия.</em></strong> Должна существовать процедура преобразования параллельного алгоритма в последовательный алгоритм и наоборот.</p>
<p>Итак, если даже где-то в листинге программы, например, обычный оператор for заменен на «параллельный» - parallel for, есть fork – join  и т.д. и т.п., а вычислительная сложность алгоритма осталась неизменной, пусть даже при увеличении скорости работы, то это все … «ручка» и не более того. Параллелизм, как качественно иное программирование, тут, скорее всего, не причем. Или, если и присутствует, то минимально. Как «регулятор скорости».</p>
<p>Меня в теории и практике параллельных процессов уже мало интересует 1) порождение параллельных процессов 2) их взаимодействия между собой и 3) их синхронизация. Мне важно есть ли алгебра параллельных процессов и ее возможности. Без алгебры (математики) процессов теория параллельных вычислений подобна миру без арифметики, а само параллельное программирование остается по своей сути пещерным, несмотря даже на увеличившееся число узлов, ядер и/или количество потоков. Есть алгебра – будет и перечисленное, а даже наличие п.п. 1, 2, 3 не ведет к алгебре. Хотя даже отсутствие алгебры – не повод отказываться от дополнительных ядер. Все же это лучше, чем ни чего (в смысле – одно ядро) <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Но алгебра алгебре рознь… К счастью, или на чью-то беду, есть задачки, решить строго которые мы можем только при наличии алгебры. Иначе - лишь на … «бумажке». Чтобы понятно было о чем речь, решение одной такой задачи - RS-триггер представлено в  книге Шалыто А.А. «SWITCH-технология. Алгоритмизация и программирование задач логического управления», Глава 4, стр.81-83, о построении ГП для RS-триггеров (http://is.ifmo.ru/books/switch_pdf/_switch4.pdf). Это еще, правда, не алгебра, но уже и не … «бумажка». Кстати, еще одно объяснение «на пальцах» на тему генерации  триггера представлено в вышедшей только что книге: Лехин С.Н. Схемотехника ЭВМ. BHV-СПб, 2010г, 672 с.  - стр. 280.</p>
<p>Вопрос задан и на него должен быть ответ. Он просто обязан быть.  Даже если его пока нет. Хотя понятно, где его искать – в теории и только в ней. Вникая в нее, дополняя и развивая, если необходимо, ее…</p>
<p>Правда, может,  ответ знает пока только ... Дед Мороз?</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/12/28/2002872/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Тридцать три шага назад!? – часть II</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/11/17/ii-2/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/11/17/ii-2/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 11:24:10 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[Разработка софта]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/11/17/ii-2/</guid>
		<description><![CDATA[В 50-е годы прошлого века Алан Тьюринг в своей знаменитой работе «Могут ли машины мыслить?»  предложил  игру в имитацию. Суть в том, что в одну  комнату помещают машину, в другую человека, и если нельзя распознать, кто где, то дается положительный ответ на заданный вопрос. А можем ли мы по аналогии ответить, какая машина, параллельная или последовательная, находится в комнате?]]></description>
			<content:encoded><![CDATA[<p>В 50-е годы прошлого века Алан Тьюринг в своей знаменитой работе «Могут ли машины мыслить?»  предложил  игру в имитацию. Суть в том, что в одну  комнату помещают машину, в другую человека, и если нельзя распознать, кто где, то дается положительный ответ на заданный вопрос. А можем ли мы по аналогии ответить, какая машина, параллельная или последовательная, находится в комнате?</p>
<p>При анализе библиотеки TBB ей были заданы «вопросы» в форме разных алгоритмов вычисляющих числа Фибоначчи. В результате было высказано предположение, что TBB не делает алгоритм параллельным. И это, несмотря использование ядер? Парадоксально? Странное на первый взгляд утверждение базируется на том, что параллельный рекурсивный алгоритм, созданный на базе аналогичного последовательного алгоритма, должен иметь вычислительную сложность, выражаемую линейной зависимостью - O(n). Но с какой такой бухты-барахты мы это взяли? …</p>
<p>Создадим модели императивного и рекурсивного последовательных алгоритмов, вычисляющих числа Фибоначчи, и убедимся, что они эквивалентны по поведению исходным алгоритмам. Это докажет, что выбранная вычислительная модель и процедура перехода к ней не искажают свойств моделируемых алгоритмов. Затем, применив эту же методику для параллельных алгоритмов, мы уже по свойствам моделей будем судить о свойствах анализируемого алгоритма.</p>
<p>На рис.1 приведена блок-схема императивного алгоритма вычисления чисел Фибоначчи, исходный код которого на языке С++ приведен в листинге 1. Для построения эквивалентной модели в форме конечного автомата проведем процедуру разметки блок-схемы точно так же, как это было показано в первой части для параллельного рекурсивного алгоритма. Сама разметка показана там же на рис.1, а граф эквивалентного автомата на рис.2.  На рис.3 приведен граф автомата, который эквивалентен последовательному рекурсивному алгоритму.</p>
<pre name="code" class="cpp">
float fib (int n)
{
  int i;
  float y, fib1, fib2;
  if (n <= 1) return y=1;
  for (fib1 = fib2 = 1, i=2; i <=n; i++)
  {
    y = fib1+fib2; fib1 = fib2; fib2 = y;
  }
  return (y);
}
// Листинг 1. Программа для вычисления чисел Фибоначчи
</pre>
<div id="attachment_2002557" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1811-d0b1d181-d0bfd0bed181d0bbd0b8d0bcd0bfd0b5d180d0b0d182d0b8d0b2d0bdd18bd0b93.jpg"><img class="size-medium wp-image-2002557" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1811-d0b1d181-d0bfd0bed181d0bbd0b8d0bcd0bfd0b5d180d0b0d182d0b8d0b2d0bdd18bd0b93-300x285.jpg" alt="Рис. 1. Блок-схема размеченного императивного алгоритма вычисления чисел Фибоначчи" width="300" height="285" /></a><p class="wp-caption-text">Рис. 1. Блок-схема размеченного императивного алгоритма вычисления чисел Фибоначчи</p></div>
<div id="attachment_2002559" class="wp-caption alignnone" style="width: 271px"><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1812-d0b0d0b2d182d0bed0bcd0b0d182-d0bfd0bed181d0bbd0b8d0bcd0b5d180d0b0d182d0b8d0b2d0bdd18bd0b91.jpg"><img class="size-medium wp-image-2002559" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1812-d0b0d0b2d182d0bed0bcd0b0d182-d0bfd0bed181d0bbd0b8d0bcd0b5d180d0b0d182d0b8d0b2d0bdd18bd0b91-261x300.jpg" alt="Рис.2. Граф автомата императивного алгоритма" width="261" height="300" /></a><p class="wp-caption-text">Рис.2. Граф автомата императивного алгоритма</p></div>
<div id="attachment_2002560" class="wp-caption alignnone" style="width: 289px"><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1813-d0b0d0b2d182d0bed0bcd0b0d182-d0bfd0bed181d0bbd180d0b5d0bad183d180d181d0b8d18f1.jpg"><img class="size-medium wp-image-2002560" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1813-d0b0d0b2d182d0bed0bcd0b0d182-d0bfd0bed181d0bbd180d0b5d0bad183d180d181d0b8d18f1-279x300.jpg" alt="Рис.3. Граф автомата последовательного рекурсивного алгоритма" width="279" height="300" /></a><p class="wp-caption-text">Рис.3. Граф автомата последовательного рекурсивного алгоритма</p></div>
<p>Теперь у нас есть две обычных программы и две автоматных модели. Доказательство того, что вычислительная сложность в результате перехода от одной модели к другой не претерпела изменений, сводится к демонстрации того, что дискретное время автоматных моделей  изменяется по тому же закону, что и реальное время работы эквивалентных обычных программ.</p>
<p>В таблицу 1 сведены результаты тестирования обычных и автоматных алгоритмов. В ее первой строке – номер числа в ряду Фибоначчи, в следующих двух - реальное время работы обычных алгоритмов, а в четвертой и пятой - дискретное время их автоматных аналогов. Графики эффективности, приведенные к времени 20-го числа обычного императивного алгоритма (первое значение во второй строке таблицы) показаны на рис.4. Из их полного совпадения следует, что выбранная модель и методика построения эквивалентных моделей не влияют на его вычислительную сложность. Напомним, что под вычислительной сложностью понимается зависимость времени работы алгоритма от значения входных данных.</p>
<blockquote><p><code>Таблица 1<br />
20       21       22       23       24       25       26       27       28<br />0,002    0,002    0,002    0,003    0,003    0,003    0,003    0,003    0,003<br />0,572    0,931    1,499    2,427    3,948    6,376    10,307   16,636   26,997<br />79       83       87       91       95       99       103      107      111<br />65672    106262   171638   278204   450146   728354   1178504  1906862  3085370<br />
</code></p></blockquote>
<blockquote><p><code>Таблица 2<br />
20       21       22       23       24       25       26       27       28<br />0,002    0,002    0,002    0,003    0,003    0,003    0,003    0,003    0,003<br />0,572    0,931    1,499    2,427    3,948    6,376    10,307   16,636   26,997<br />59       62       65       68       71       74       77       80       83<br />
</code></p></blockquote>
<p>В целях наглядности включим в новую таблицу времена обычных алгоритмов из таблицы 1 и дискретное время работы параллельного рекурсивного алгоритма. Графики вычислительной сложности, приведенные ко времени императивного алгоритма, по данным таблицы 2, представлены на рис. 5. Их вид убеждает, что вычислительная сложность параллельного алгоритма имеет тот же вид, что и вычислительная сложность последовательного императивного алгоритма. Просто параллельный алгоритм в абсолютном выражении тратит на вычисление меньше времени. В данном случае условного времени – дискретного.</p>
<div id="attachment_2002562" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1814-d0b3d180d0b0d184d0b8d0bad0b8-d18dd184d184d0b5d0bad182d0b8d0b2d0bdd0bed181d182d0b8-d0b0d0bbd0b3d0bed180d0b8d182d0bcd0be1.jpg"><img class="size-medium wp-image-2002562" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1814-d0b3d180d0b0d184d0b8d0bad0b8-d18dd184d184d0b5d0bad182d0b8d0b2d0bdd0bed181d182d0b8-d0b0d0bbd0b3d0bed180d0b8d182d0bcd0be1-300x186.jpg" alt="Рис. 4. Графики эффективности алгоритмов (Ряд 1,2 – обычные, Ряд 3,4 – автоматные)" width="300" height="186" /></a><p class="wp-caption-text">Рис. 4. Графики эффективности алгоритмов (Ряд 1,2 – обычные, Ряд 3,4 – автоматные)</p></div>
<div id="attachment_2002563" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1815-d0b3d180d0b0d184d0b8d0bad0b8-d18dd184d184d0b5d0bad182d0b8d0b2d0bdd0bed181d182d0b8-d0b0d0bbd0b3d0bed180d0b8d182d0bcd0be.jpg"><img class="size-medium wp-image-2002563" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1815-d0b3d180d0b0d184d0b8d0bad0b8-d18dd184d184d0b5d0bad182d0b8d0b2d0bdd0bed181d182d0b8-d0b0d0bbd0b3d0bed180d0b8d182d0bcd0be-300x189.jpg" alt="Рис.5. Графики вычислительной сложности алгоритмов (Ряд 1, 2 – обычные, Ряд 3 – параллельный рекурсивный)" width="300" height="189" /></a><p class="wp-caption-text">Рис.5. Графики вычислительной сложности алгоритмов (Ряд 1, 2 – обычные, Ряд 3 – параллельный рекурсивный)</p></div>
<p>Из совпадения вычислительной сложности алгоритмов следует, что, не зная какой алгоритм – рекурсивный или императивный реализует «черный ящик», сложно определить устройство внутренностей «ящика». Можно было бы судить по реальному времени, т.к. параллельный по идее должен быть быстрее. Но, это еще, как говорится, не факт! Может быть, правда, пока? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Однако, если известно точно, что «ящик» реализует рекурсивный алгоритм, то линейный характер вычислительной сложности говорит о том, что oн параллельный, а если экспоненциальный (аппроксимация с помощью функции СТЕПЕНЬ(число; степень из Excel приводит к зависимости – O(2^(N/1,44))  – последовательный.</p>
<p>… Но если вернутся к цели нашего исследования – анализу вычислительной сложности алгоритмов, то проблема, безусловно, не в том, что TBB замедлила в данном конкретном случае работу алгоритмов в реальном времени. В теории анализ алгоритмов не связывают с реальным временем, а рассматривают условное время. Например, когда «зернистость» будет соответствовать требованиям TBB (в пределах 1000 инструкций на такт условного времени), то, скорее всего, время работы уменьшится и возможно даже, как в случае с числами Фибоначчи, пропорционально числу ядер. Проблема в другом: свойства алгоритма, как показало тестирование, остались прежними – последовательными! Но смысл введения множества ядер не только и не столько в простом увеличении скорости работы программ, а в увеличение скорости за счет качественно иного программирования – параллельного. А последнее, если верить теории, должно привести к изменению его вычислительной сложности. Пока мы этого не наблюдаем (или не можем увидеть?).</p>
<p>Так может ли речь идти о параллельном алгоритме, если его свойства остаются последовательными? Для внешнего наблюдателя, играющего, например, в упомянутую выше имитацию, подобное «распараллеливание» эквивалентно простому увеличению тактовой частоты «ящика» – при увеличении скорости его работы, и уменьшении – при увеличении времени работы. Напомним, что в случае TBB скорость для однопоточной параллельной версии сначала уменьшилась в 66 раз, а потом для двух ядер увеличилась в два раза, т.е. в конечном итоге уменьшилась в 33 раза при сохранении вычислительной сложности (?).</p>
<p>Но тогда, если следовать правилам «игры» или, что точнее, теории алгоритмов, речь должна идти скорее о неких ухищрениях, в каких-то случаях повышающих, а в большинстве, как можно предположить, скорее понижающих,  скорость работы  программ. При этом сама причина уменьшения скорости в том, что под упомянутые требования зернистости подпадает лишь малая часть параллельных алгоритмов.<br />
Оценивая результаты тестирования алгоритмов, можно также возразить – просто мало ядер! Настолько мало, что их число никак не сказывается на свойствах алгоритма. Но будет ли достаточно 4-х, 8-ми и т.д. ядер? И, действительно, для параллельного рекурсивного алгоритма почти любое доступное их число сейчас и даже предполагаемое в будущем – капля в море, т.к. речь должна идти о сотнях тысяч ядер!</p>
<p>Оценку вычислительной сложности параллельного алгоритма можно и даже нужно выполнять исходя из понятия виртуального параллелизма. В этом случае и время должно быть виртуальным или условным. В автоматной модели условное/виртуальное время – это дискретное время. А как узнать виртуальное время (в теории, напомним, чаще говорят об относительном времени) работы многопоточного  алгоритма? Подсчитывать число инструкций, в том числе и выполняемых параллельно?...</p>
<p>PS: Тестирование параллельного рекурсивного алгоритма на MC# убеждает, что и  он имеет вычислительную сложность, как и у последовательного рекурсивного алгоритма.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/11/17/ii-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Тридцать три шага назад!?</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/11/06/2002442/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/11/06/2002442/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 11:29:04 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[TBB]]></category>
		<category><![CDATA[Фибоначчи]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/11/06/2002442/</guid>
		<description><![CDATA[Если доверять классикам, то иногда нужно сделать шаг назад, чтобы потом - два шага вперед. А что же в параллельном программировании? Куда мы шагаем, что и в чем выигрываем? Чтобы легче было шагать, нам в помощь дадены разнообразные средства для параллельного программирования – языки, библиотеки и т.п. Обратим свой взгляд на библиотеку Intel® TBB (Intel® Threading Building Blocks) и посмотрим, куда она нас приведет.]]></description>
			<content:encoded><![CDATA[<p>На мою просьбу написать рекурсивный параллельный алгоритм на базе TBB так никто и не откликнулся. Алексей Куканов – молчит, прошу прощения, как рыба, несмотря на мои неоднократные обращения к нему лично, у остальных – свои проблемы и, видимо, интересы. Но, как мне представляется, интересы у нас одни – параллельное программирование, а потому нужен все же диалог. Хотя бы… ну хоть кто-нибудь намекнул, что данный алгоритм приведен в документации к Intel® TBB (Intel® Threading Building Blocks)! Или, может, Алексей не следит за блогами, а остальные не знакомы с ее описанием? И то и другое достаточно удивительно, если не сказать странно! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Тем не менее, к вящей радости проблема нашла свое решение – сам нашел! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Но – к делу! Если доверять классикам, то иногда нужно сделать шаг назад, чтобы потом - два шага вперед. А что же в параллельном программировании? Куда мы шагаем, что и в чем выигрываем? Чтобы легче было шагать, нам в помощь дадены разнообразные средства для параллельного программирования – языки, библиотеки и т.п. Обратим свой взгляд на библиотеку Intel® TBB (Intel® Threading Building Blocks) и посмотрим, куда она нас приведет. Будет ли наш «параллельный путь» легче и/или быстрее.</p>
<p>Собираясь в дальний путь, настоятельно рекомендуется проверить средства передвижения. В противном случае – это халатность, граничащая с безрассудством. Целям проверки в дистрибутиве TBB служат ее тестовые примеры. Выберем из множества примеров, имеющихся в составе дистрибутива, один из самых простых и наглядных – вычисление чисел Фибоначчи. Это проект fibonacci из дистрибутива TBB.</p>
<p>Числа Фибоначчи нам известны, или должны быть известны, с юных лет (см., например, «Энциклопедический словарь юного математика»). Результаты тестовых прогонов для чисел в диапазоне от 20-го до 28-го числа по обычным алгоритмам – императивному и рекурсивному и параллельному аналогу рекурсивного алгоритма сведены в таблицу 1.</p>
<blockquote><p><code>Таблица 1.<br />
20       21       22       23       24       25      26       27       28<br />0,002033 0,002187 0,002333 0,002502 0,002678 0,00282 0,002978 0,003184 0,003376<br />0,5717   0,9314   1,499674 2,427057 3,948402 6,3763  10,30745 16,63595 26,99721<br />38,277   61,795   100,736  162,243  264,04   427,75  691,78   1119,94  1808,8<br />19,626   32,397   50,981   82,236   132,24   214,11  344,99   557,68   903,44</code></p></blockquote>
<p>В ней первая строка соответствует номеру числа, вторая - реальному времени работы императивного алгоритма, третья - рекурсивного, четвертая и пятая – однопоточной и двухпоточной версиям рекурсивного алгоритма на базе TBB. Рекурсивный алгоритм заимствован из документа Tutoril комплекта документации к TBB, используемый процессор - Intel® Core™2 CPU 6400 @ 2,13 GHz.</p>
<p>Поскольку тестирование проводилось на двухядерном процессоре, то время работы «двухядерного» варианта меньше ровно в два раза. Эффект от многоядерности налицо! Однако, если мы сравним время работы алгоритмов во второй строке и в четвертой, то имеем замедление работы более чем в тридцать три раза (на первую строку лучше не смотреть!). Или, другими словами, чтобы достичь скорости исходного алгоритма, запрограммированного обычным способом и на одном ядре, нам нужно будет минимум шестьдесят шесть (!) ядер, чтобы хотя бы приблизиться к нему по производительности. Глядя на таблицу и вспоминая вопрос Сергея Вильянова – «Есть ли реальная польза от многоядерных процессоров?», напрашивается один ответ – нет, т.к. медленно!</p>
<p>При такой скорости многоядерности сложно быть «торопливым» (см. <a href="http://software.intel.com/ru-ru/blogs/2009/02/12/2000639/">http://software.intel.com/ru-ru/blogs/2009/02/12/2000639/</a>). Мечталось-то, ведь, совсем о другом! Но если серьезно, то подобные факты не способствуют оптимизму, т.к. желаемое и в этот раз только отодвинулось, причем на достаточно большое расстояние, т.к. о более чем шестидесятиядерном процессоре сейчас, думаю, даже мечтать нельзя, хотя и ходят разговоры о тысячах ядер!</p>
<p>Но проблема-то, как это ни удивительно, не в скорости. Скорость - это как раз поправимо. Проблема глубже. Если мы немного «пошаманим» с таблицей, то вдруг выясняется, что параллелизма как такового библиотека TBB в приложение не добавляет. Скрытое становится явным, если мы посмотрим на графики алгоритмов, которые приведены к времени вычисления императивного алгоритма (к вычислению 20-го числа).</p>
<p>На рис. 1 графики обычного рекурсивного алгоритма и его параллельных аналогов совпадают идеально, имея экспоненциальный характер роста зависимости скорости работы от номера числа в ряду Фибоначчи. А вот скорость императивного алгоритма, как легко видеть, представляет собой линейную функцию (см. ряд 1 на рис.1).</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d181-11.jpg"><img class="size-medium wp-image-2002441 alignnone" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d181-11-300x169.jpg" alt="" width="300" height="169" /><br />
</a><em>Рис.1. График зависимости скорости работы программы от n</em></p>
<p>Но, может, так оно и должно быть? Т.е. если мы имеем обычный рекурсивный алгоритм и его эквивалентный параллельный аналог, то и характер их поведения должен быть похожим в силу свойств алгоритма? Но зачем тогда параллелизм? Тем более, как можно видеть, мы только усугубляем ситуацию, усложняя программирование (см. на код с TBB) да еще и многократно замедляя работу программ.</p>
<p>Но, слава Богу (или – нам?), можно показать, что ситуация не столь уж удручающая. Параллельным программированием заниматься можно и нужно. Так, для нашего случая зависимость скорости расчета от номера числа у параллельного рекурсивного алгоритма должна быть столь же линейна, как и у последовательного императивного алгоритма. Уже только это - источник большого оптимизма. Важно переломить тенденцию, т.к. скорость увеличить достаточно просто (правда, до известных пределов, которых мы, к сожалению, уже фактически достигли). Ну а о том, что это возможно, в следующем блоге.</p>
<p>Весьма важное замечание. Сейчас мы в поиске надежных, эффективных и адекватных средств и/или моделей параллельных вычислений. В этом смысле параллельный рекурсивный алгоритм оказался «лакмусовой бумажкой» тестирования библиотеки на адекватность параллелизму. Пока, как показало испытание, несмотря на заявленный параллелизм, ТВВ не влияет качественно на свойства алгоритма (скажем осторожно – в данном случае). Да, отдавая ей должное, TBB использует множество ядер (см. таблицу 1), но при этом не добавляет параллельных свойств алгоритму. Что делать? Это уже вопрос, наверное, к … Алексею. Если, конечно, он не отмолчится в очередной раз <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>И еще. Сороковое число обычный рекурсивный алгоритм считает почти за 9 сек, параллельный двухпоточный – за 290 сек! Все то же сакральное - «тридцать три». Параллелизм – полный! <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>А интересно, какую зависимость получим, протестировав параллельный рекурсивный алгоритм на MC#? Этого я, честно, пока не знаю. Вот выяснением этого и займусь. Проблема только в одном – мне известно, что уже на 16-м/17-м числе программа на MC# аварийно завершает свою работу. Значит, нужно выбирать другой диапазон…</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/11/06/2002442/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Модель – для понта, язык – для дела?</title>
		<link>http://software.intel.com/ru-ru/blogs/2009/10/15/2002309/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2009/10/15/2002309/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 12:07:38 +0000</pubDate>
		<dc:creator>vlubch</dc:creator>
				<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[Разработка софта]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2009/10/15/2002309/</guid>
		<description><![CDATA[Давайте разберемся, действительно ли, как это часто преподносится, модель для наукообразия или, попросту, – для понта и только лишь язык программирования – для дела? На примере вычисления чисел ряда Фибоначчи мы рассмотрим параллельные идеи в рамках широко известных языков С# и С++.]]></description>
			<content:encoded><![CDATA[<p>Перефразируя произнесенную в <a href="http://software.intel.com/ru-ru/blogs/2009/08/27/2001970/">http://software.intel.com/ru-ru/blogs/2009/08/27/2001970/</a> фразу о ружьях и ножах из фильма «Карты, деньги, два ствола», давайте разберемся, действительно ли, как это часто преподносится, модель для наукообразия или, попросту, – для понта и только лишь язык программирования – для дела? На примере вычисления чисел ряда Фибоначчи мы рассмотрим параллельные идеи в рамках широко известных языков С# и С++ (подробнее см. соответственно [1] и [2]).</p>
<p>Имя Леонардо Фибоначчи (Леонардо Пизанского) часто упоминается в связи со следующей числовой последовательностью:<br />
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …<br />
Данный ряд натуральных чисел, называемый рядом чисел Фибоначчи, записанный как<br />
a0, a1, a2, a3, . . .<br />
можно описать следующим образом:<br />
a0 = 1, a1 = 1, и<br />
ai = ai-1 + ai-2,  для  i  &gt;= 2.</p>
<p>Откуда взяться параллелизму, если о нем в постановке задачи не говорится ни слова? Оставив в стороне пока еще, как показывает практика, скорее фантастические планы по автоматическому распараллеливанию всего и вся, мы рассмотрим явный параллелизм. При этом это будет, пожалуй, самый простой случай, когда в уже известном последовательном алгоритме некоторые из его конструкций/операторов заменяются один в один на аналогичные, но параллельные. Мы сравним фактически один и тот же алгоритм, но на базе разных параллельных  моделей вычислений.</p>
<p>Одна из тенденций реализации параллелизма состоит в расширении существующих языков программирования. Параллельная программа на языке MC# (он же – расширенный С#[1]), вычисляющая числа Фибоначчи, представлена  листингом 1. Это известный последовательный рекурсивный алгоритм, в котором рекурсивные вызовы заменены на параллельно исполняемые. Введенный  параллелизм несколько изменяет исходный последовательный алгоритм. Результат таких изменений в форме параллельной блок-схемы (БС) показан на рис. 1.</p>
<p>Приведенная блок-схема в явной форме отражает параллельные алгоритмические свойства решения. При этом на рис.1 переход (в терминах сети Петри),  из которого исходят дуги, соответствует вызову параллельно исполняемых movable-методов MC#, а переход с входящими дугами – методу типа Get (см. листинг 1). При этом, например, у перехода с входящими дугами, их число соответствует числу каналов, по которым нужно одновременно принять данные от параллельно исполняемых методов.</p>
<p>Имея модель и зная процедуры ее эквивалентного преобразования, мы можем перейти к другой модели вычислений – автоматной[2]. В целях построения эквивалентного блок-схеме конечного автомата (КА) проведем процедуру разметки БС.  Для этого нанесем на нее отметки внутренних состояний автомата, а элементы блок-схемы поименуем (см. рис.1). Именам функциональных блоков x1,…, xN  в новой модели соответствуют методы - предикаты, возвращающие булевское значение. Им будут поставлены в соответствие входные сигналы автомата. Именам y1,…, yN соответствуют методы-действия, определяющие действия автоматной алгоритмической модели вычислений. Им соответствуют выходные сигналы автомата. Граф автомата, соответствующий разметке, показан на рис.2.</p>
<p>В терминах теории программ (точнее, - теории схем программ) рис.2 – это графическая форма так называемого управления программы. Но в модель программы кроме управления входит еще два множества - множество данных и множество операций (о моделях программ подробнее см. [3]).  Поэтому рядом с графом управления автоматной программы приведено описание ее методов – предикатов и действий. Именно с их помощью выполняется анализ и преобразование данных в последовательности, определяемой управлением программы. Листинг 2 дает конкретное представление о выбранном подходе к реализации автоматной модели на языке С++.</p>
<p>Отметим, что в отличие от программ на языке MC# в автоматном С++ нет разделения на перемещаемые и неперемещаемые методы. Все методы потенциально параллельны. При этом на параллелизм предикатов ограничений нет, т.к. они не изменяют данных, а у параллельно исполняемых действий не должно быть пересечений по данным, к которым возможен одновременный доступ. Параллелизм методов отражают переходы автоматной модели, где параллелизм предикатов представляют конъюнкции входных сигналов, а параллелизм действий – набор выходных сигналов автомата.</p>
<p>Отвлечемся на мгновение от самого процесса вычисления чисел Фибоначчи… Можно ли утверждать, что модель вычислений определяет мышление программиста?  Скорее да, чем нет. Сравнивая графы программ на рис.1 и 2, легко видеть, что автоматный язык лаконичнее языка блок-схем. Он несет больше информации, стимулирует на действия и мысли, которые вряд ли возникнут у того, кто пользуется языком блок-схем.</p>
<p>Внутренние состояния программы – это перекрестки, на которых программист намечает путь дальнейшего движения. Но, находясь на том или ином перекрестке-состоянии, он должен сознавать, что, переместившись, он уже вернуться к текущей ситуации просто так не сможет. Исключение – петли на графе КА, которые не содержат выходных действий. Именно в силу этого в целях упрощения модели они исключены из описания автомата. Они, задавая его переходы «по умолчанию» представляют, строго говоря, дополнение явно представленного частичного автомата до полностью определенного.</p>
<p>В автомате на рис.2 состояния-перекрестки программы можно трактовать следующим образом. Состояние автомата «f1» – начальное состояние алгоритма и одновременно состояние анализа текущего значения n – номера числа в ряду Фибоначчи; «f2» - состояние ожидания завершения вычисления предшествующих двух чисел ряда; «00» - заключительное состояние алгоритма, при переходе в которое мы знаем значение первого числа в ряду Фибоначчи или сумму предыдущих двух чисел ряда.<br />
Анализируя управление автоматной программы, можно, опираясь на теорию конечных автоматов, оценить, например, его непротиворечивость и полноту. При этом в нашем случае полностью определенный автомат – это объединение его частичной формы, представленной явно (см. рис.2), и его дополнения – автоматом с теми же состояниями, что и частичный автомат, но с переходами по умолчанию - петлями, входные условия которых представлены отсутствующими на графе конъюнкциями входных сигналов.</p>
<p>Что толку от быстро полученного, но глупого совета!? Но, как бы там ни было, программу часто встречают «по одежке», т.е. скорости ее работы. А есть случаи – системы реального времени – когда скорость отклика имеет вообще решающее значение. Для них запоздало данный, хотя и правильный, совет не нужен. Поэтому весьма желательно, чтобы хорошему мышлению соответствовали быстрые и/или хотя бы оперативно данные правильные (!) ответы. Сравнение по скорости работы программы на MC# и автоматном С++ показало, что вычисление, например, 16-го числа на первом выполняется медленнее более чем в 20 раз, чем на втором…</p>
<p>Программист может написать программу и без создания модели. Но по большому счету это не правильно, т.к. пропускается важный этап технологического процесса проектирования программы. С моделью можно делать то, что с кодом проводить крайне затруднительно: минимизация алгоритма, проверки на противоречивость и полноту, верификация и т.д. и т.п. Кстати, если подобное планируется проделать с кодом, то его приводят к определенной модели.</p>
<p>Замечание. Можно впасть в крайность и вообще игнорировать общепризнанные этапы проектирования программ. Именно такое ощущение возникает от работы некоторых программ, когда возникает подозрение, что пропущен даже этап тестирования?!</p>
<p>Автоматный подход обладает гибкостью, которая позволяет реализовать почти любой стиль «мышления» программиста. Появление новых «надежных» языков пока не очень повысило надежность программирования, да и нынешние параллельные решения все еще не оправдывают возлагавшихся на них надежд (и не только в отношении скорости). Поневоле задашься вопросами – может, не так и не то «повышаем», не то и не так «параллелим»? И как с этим разобраться, если не исследовать модели «программистского мышления»?</p>
<p>И напоследок. Без ущерба для дела мы могли бы вообще не рассматривать программный код. Модель – основное, реализация – дело техники. Безусловно, качества программы зависят от языка программирования. Но это уже больше проблема выбора средства реализации, чем самой модели. Понимания пользы модели позволяет преодолеть  любые сложности на пути ее эффективной реализации. Вплоть до создания языка программирования и аппаратной архитектуры для ее поддержки.<br />
Литература<br />
1.	Гузев В., Сердюк Ю. Введение в параллельное программирование на языке MC#. Переславль Залесский/Москва. 2007. <a href="http://u.pereslavl.ru/~vadim/MCSharp/docs/pguide/pguide.doc">http://u.pereslavl.ru/~vadim/MCSharp/docs/pguide/pguide.doc</a><br />
2.	Любченко В.С. Конечно-автоматная технология программирования.  <a href="http://www.softcraft.ru/design/katech.shtml">http://www.softcraft.ru/design/katech.shtml</a><br />
3.	Наумов Н.А. О некоторых подходах к расширению языков программирования. <a href="http://eidos.kiam.ru/group/pod.html">http://eidos.kiam.ru/group/pod.html</a>.</p>
<p>Листинг 1:</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b31.jpg"><img class="alignnone size-medium wp-image-2002305" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b31-300x160.jpg" alt="" width="300" height="160" /></a></p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b31.jpg"></a><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1811.jpg"><img class="alignnone size-medium wp-image-2002306" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1811-296x300.jpg" alt="" width="296" height="300" /></a></p>
<p>Листинг 2:</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b32.jpg"><img class="alignnone size-medium wp-image-2002307" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b32-300x247.jpg" alt="" width="300" height="247" /></a></p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d0bbd0b8d181d182d0b8d0bdd0b32.jpg"></a><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1812.jpg"><img class="alignnone size-medium wp-image-2002308" src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/d180d0b8d1812-300x114.jpg" alt="" width="300" height="114" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2009/10/15/2002309/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

