<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2russianfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-7754674872362895099</atom:id><lastBuildDate>Fri, 03 Feb 2012 05:27:03 +0000</lastBuildDate><category>thread-safety</category><category>templates</category><category>erlang</category><category>fp</category><category>web</category><category>programming</category><category>boost</category><category>holly wars</category><category>music</category><category>lua</category><category>blog</category><category>asio</category><category>C#</category><category>exceptions</category><category>C++</category><category>win32</category><category>fsharp</category><category>thoughts</category><category>OOP</category><category>windows</category><category>work</category><category>unit-test</category><category>.NET</category><category>google</category><category>codejam</category><category>жизнь</category><title>Очень серьезный блог</title><description /><link>http://evgeny-lazin.blogspot.com/</link><managingEditor>noreply@blogger.com (Евгений Лазин)</managingEditor><generator>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/evgeny-lazin" /><feedburner:info uri="evgeny-lazin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fevgeny-lazin" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fevgeny-lazin" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/evgeny-lazin" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fevgeny-lazin" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fevgeny-lazin" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://lenta.yandex.ru/settings.xml?name=feed&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fevgeny-lazin" src="http://lenta.yandex.ru/i/addfeed.gif">?????? ? ??????.?????</feedburner:feedFlare><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-8852751459251579261</guid><pubDate>Tue, 15 Nov 2011 19:32:00 +0000</pubDate><atom:updated>2011-11-16T13:18:22.214+04:00</atom:updated><title>Threaded vs Event driven</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Как правило, при создании сервера перед нами глобально стоит всегда один и тот же выбор - threaded или event driven.&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
Многопоточный (threaded) сервер - проще в реализации, на каждое клиентское соединение создается отдельный поток, весь ввод/вывод через это соединение происходит в данном потоке, синхронно. Преимущество данного подхода - относительная простота реализации, недостаток - плохая масштабируемость с ростом числа одновременных соединений (запускать&amp;nbsp;много потоков - плохо).&lt;br /&gt;
Event driven сервер использует механизм IOCP (если речь идет о windows), вся логика обработки запросов выполняется асинхронно, в обработчиках событий. Преимущество данного подхода состоит в том, что клиентское соединение больше не привязано к потоку. Недостатки - сложность разработки, логика распределена по множеству обработчиков событий и сложность отладки. Понимать логику работы event driven сервера не всегда просто, отсюда все остальные сложности.&lt;/div&gt;
&lt;div&gt;
Именно поэтому, зачастую стоит выбрать threaded архитектуру, главное понять в каких случаях это можно сделать, а в каких - нет.&lt;br /&gt;
&lt;br /&gt;
Итак, введем следующие обозначения:&lt;/div&gt;
&lt;div&gt;
T - пропускная способность сервера, количество запросов в секунду.&lt;/div&gt;
&lt;div&gt;
C - время, затрачиваемое процессором на выполнение запроса (CPU time).&lt;/div&gt;
&lt;div&gt;
I - время, затрачиваемое потоком на синхронное выполнение операций ввода/вывода (I/O time).&lt;/div&gt;
&lt;div&gt;
N - количество процессоров.&lt;/div&gt;
&lt;div&gt;
M - количество потоков.&lt;br /&gt;
Я считаю что мы пишем сервер, который выполняет запросы, каждый запрос выполняется фиксированное время, часть времени тратится на выполнение операций ввода вывода - I, а часть на обработку - C.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Максимальная пропускная способность event driven сервера - T = N/C. Это должно быть интуитивно понятно, пропускная способность максимальна тогда, когда процессор загружен обработкой запросов на 100%.&lt;br /&gt;
Пропускная способность многопоточного сервера - T = M/(I + C). Последняя формула справедлива только в том случае, если процессор загружен не полностью, иначе, увеличение M не будет приводить к увеличению пропускной способности сервера. Если эта зависимость кажется вам не очевидной, представьте что у нас есть однопоточный сервер (М = 1), его пропускная способность должна быть обратно пропорциональна сумме I + C, так как весь ввод/вывод выполняется синхронно и блокирует поток.&lt;br /&gt;
Наша задача состоит в том, что-бы определить такое количество потоков, при котором пропускная способность многопоточного сервера является максимальной. Очевидно, она будет равна максимально пропускной способности event driven сервера:&lt;/div&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;T = N/C = M/(I + C);&lt;br /&gt;M = N (I/C + 1);&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
Как это можно использовать на практике? Очень просто, допустим, выполнение запроса у нас занимает 1мкс, а операции ввода вывода - 1мс. При N = 1, подставляем значения в формулу - M = 0.001/0.000001 + 1 = 1001, ровно столько потоков нам нужно для того, чтобы полностью загрузить один процессор. Очевидно, что в данном случае лучше использовать event driven архитектуру.&lt;/div&gt;
&lt;div&gt;
Другой пример, время обработки С = 100мкс, время выполнения ввода/вывода I = 1мс, M = 11. В данном случае можно обойтись threaded архитектурой сервера.&lt;br /&gt;
&lt;br /&gt;
У вас может возникнуть следующий вопрос, что будет, если во втором примере к серверу подключится множество клиентов, намного больше&amp;nbsp;одиннадцати&amp;nbsp;и не лучше ли выбрать в этом случае event driven подход? Ответ - а черт его знает, в режиме перегрузки обе архитектуры работают плохо, в рамках event driven подхода будет увеличиваться среднее время обработки отдельного запроса и объем используемой памяти. Ровно тоже самое будет происходить с threaded сервером, который запустит слишком много потоков. Возможно, event driven сервер будет работать в режиме сильной перегрузки немного лучше, но это вовсе не обязательно и вообще зависит от конкретной реализации.&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-8852751459251579261?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/Coks8IaOCJc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/Coks8IaOCJc/threaded-vs-event-driven.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>1</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/11/threaded-vs-event-driven.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2458403310601998777</guid><pubDate>Sun, 02 Oct 2011 16:15:00 +0000</pubDate><atom:updated>2011-10-03T09:54:27.888+04:00</atom:updated><title>Disruptor</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Продолжая &lt;a href="http://evgeny-lazin.blogspot.com/2011/10/blog-post.html"&gt;разговор об очередях&lt;/a&gt;.&amp;nbsp;Не так давно, Мартин Фаулер опубликовал статью с описанием архитектуры &lt;a href="http://martinfowler.com/articles/lmax.html"&gt;LMAX&lt;/a&gt;, это что-то вроде трейдинговой платформы, которая обрабатывает очень много мелких сообщений. Как мы уже знаем, сообщения можно обрабатывать с помощью конвейера, но обычные очереди сообщений оказывается не всегда хорошо подходят для этой цели.&lt;br /&gt;
&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
Представим себе некую сложную систему из очередей и потоков, у нас есть N потоков, которые связаны N + 1 очередями. Пускай очереди реализованы на основе массивов. У нас есть множество массивов, каждое сообщение N + 1 раз записывается в массив и N + 1 раз читается из массива, при этом происходит N + 1 изменений переменных head и tail разных очередей. Даже если все очереди, это SPSC очереди, это несколько избыточно. Для решения этой проблемы, разработчики LMAX создали библиотеку &lt;a href="http://code.google.com/p/disruptor/"&gt;Disruptor&lt;/a&gt; для java. Помимо этого, уже существуют .NET и С++ порты, примеры в этой статье будут использовать .NET порт.&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-BtXLpe2OfDI/Toh_6VRuhoI/AAAAAAAAYu4/RByuAfGcnM0/s1600/paint+%25287%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;strike&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-BtXLpe2OfDI/Toh_6VRuhoI/AAAAAAAAYu4/RByuAfGcnM0/s320/paint+%25287%2529.jpg" width="320" /&gt;&lt;/strike&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a name='more'&gt;&lt;/a&gt;В общем, disruptor это один большой кольцевой буфер, с помощью которого можно заменить целый огород из очередей. Во время создания, кольцевому буферу передается его размер и фабрика для создания объектов. Помимо этого, буфер можно немного настроить, он может использовать разные механизмы ожидания, блокирующий, yield (передает управление другому потоку) и spin wait. Буфер заполняется созданными фабрикой объектами, которые из него никогда не удаляются.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial;"&gt;&lt;span style="font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;  var&lt;/span&gt;&amp;nbsp;ringBuffer&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;RingBuffer&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;(
    ()&amp;nbsp;=&amp;gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;(),
    100&amp;nbsp;*&amp;nbsp;1024,
&lt;span style="color: #484848; font-weight: bold;"&gt;    ClaimStrategyFactory&lt;/span&gt;.&lt;span style="color: #555555; font-weight: bold;"&gt;ClaimStrategyOption&lt;/span&gt;.SingleThreaded,
    &lt;span style="color: #484848; font-weight: bold;"&gt;WaitStrategyFactory&lt;/span&gt;.&lt;span style="color: #555555; font-weight: bold;"&gt;WaitStrategyOption&lt;/span&gt;.Yielding);&lt;/span&gt;
&lt;/pre&gt;
&lt;span style="font-family: inherit;"&gt;Далее, пользователь библиотеки может создать множество потребителей, причем потребители могут работать как параллельно, при этом каждое сообщение будет обработано всеми параллельно включенными потребителями, а так же последовательно. У вас не получится сделать многие вещи, например, создать цикл или сделать так, чтобы сообщения обрабатывались только одним из параллельных потребителей. &lt;/span&gt;&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;  var&lt;/span&gt;&amp;nbsp;cons&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueConsumer&lt;/span&gt;(COUNT);
  ringBuffer&lt;/pre&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial;"&gt;&lt;span style="font-family: Consolas; font-size: 15px;"&gt;    .ConsumeWith(&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;())
    .Then(&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;(),&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Decrementer&lt;/span&gt;())
    .Then(cons);&lt;/span&gt;
&lt;/pre&gt;
&lt;div&gt;
&lt;span style="font-family: inherit;"&gt;В данном примере мы создаем конвейер из трех этапов, на пером этапе каждое сообщение будет обработано одним потребителем Incrementer, на втором двумя(Incrementer и Decrementer), и на третьем - одним потребителем типа ValueConsumer. При этом сообщение останется в массиве после того, как все потребители его обработают, в дальнейшем его перезапишет производитель. Потребители, это объекты, реализующие интерфейс IBatchHandler&amp;lt;T&amp;gt;:&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;  class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IBatchHandler&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;
  {
&lt;span style="font-weight: bold;"&gt;    public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnAvailable(&lt;span style="font-weight: bold;"&gt;long&lt;/span&gt;&amp;nbsp;sequence,&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data)&amp;nbsp;{
      data.Value++;
    }&lt;/pre&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;    public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnEndOfBatch()&amp;nbsp;{
    }
  }&lt;/pre&gt;
&lt;span style="font-family: inherit;"&gt;Хочу обратить внимание на то, что потребитель изменяет параметр data, параметр data, это элемент кольцевого буфера, sequence - номер сообщения. После этого, пользователь библиотеки должен создать producer barrier - объект, с помощью которого он будет добавлять новые сообщения. Producer barrier может быть многопоточным, тогда внутри себя он будет использовать атомарные операции, либо однопоточным, тогда он будет работать немного быстрее в случае, если вызывается из одного потока.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial;"&gt;&lt;span style="font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;  var&lt;/span&gt;&amp;nbsp;pbarrier&amp;nbsp;=&amp;nbsp;ringBuffer.CreateProducerBarrier();
  ringBuffer.StartConsumers();&lt;/span&gt;
&lt;/pre&gt;
После того, как вы все это сделали, нужно вызвать метод StartConsumers, который запустит по одному потоку на каждого потребителя.&amp;nbsp;&lt;span style="font-family: inherit;"&gt;Добавление нового сообщения выглядит следующим образом:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 15px;"&gt;  &lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data;
&lt;span style="font-weight: bold;"&gt;  var&lt;/span&gt;&amp;nbsp;seq&amp;nbsp;=&amp;nbsp;barrier.NextEntry(&lt;span style="font-weight: bold;"&gt;out&lt;/span&gt;&amp;nbsp;data);
  data.Value&amp;nbsp;=&amp;nbsp;i;
  barrier.Commit(seq);&lt;/pre&gt;
&lt;br /&gt;
мы должны в первую очередь вызвать метод NextEntry, который выделит в массиве место под наш новый элемент. При этом не происходит выделение памяти, элемент массива был создан заранее. Барьер использует claim factory для получения номера очередного сообщения (параметр claim factory конструктора) именно его и возвращает метод NextEntry. Далее, нужно изменить объект, ссылку на который мы получили вызвав NextEntry, например записав в него наше сообщение и затем, вызвать метод Commit, передав в него номер сообщения.&lt;br /&gt;Такой хитрый метод записи позволяет добавлять элементы в буфер сразу из нескольких потоков без блокировок и синхронизации.&lt;span style="font-family: inherit;"&gt;Далее, будут вызываться методы OnAvailable всех потребителей в том порядке, который мы задали во время конфигурирования буфера. В этот метод также передается номер обрабатываемого сообщения, который можно использовать например для того, что-бы организовать обработку сообщений в round-robin манере, несколькими параллельными consumer-ами.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Обработчики содержат внутри себя свою текущую позицию и специальный объект, который создается с помощью wait factory, с помощью которого он может ждать появления доступных для обработки сообщений. Также, все обработчики знают о своих зависимостях и после обработки очередного сообщения "сигналят" следующему обработчику. Текущая позиция обработчика изменяется только из одного потока - потока этого обработчика, при этом генерируется write barrier. Перед тем как прочитать элемент, обработчик должен быть "разбужен" producer barrier-ом или другим обработчиком, он должен прочитать значение текущей позиции разбудившего (генерируется read barrier) и решить, сколько сообщений он может прочитать. Затем, для каждого из доступных сообщений будет вызван метод OnAvailable, а затем OnEndOfBatch.&lt;/div&gt;
&lt;div&gt;
OnEndOfBatch - позволяет обрабатывать сообщения не по оному а пачками, т.н. batch processing. Если ваш обработчик выполняет какой либо I/O, то лучше в методе OnAvailable формировать буфер для отправки(либо просто запомнить номера первого и последнего сообщений между вызовами OnEndOfBatch), а в OnEndOfBatch - непосредственно выполнять I/O.&lt;/div&gt;
&lt;div&gt;
Итак, disruptor может быть очень полезен, хотя-бы тем, что избавляет от необходимости городить и поддерживать огород из множества потоков и очередей вручную. Ну и как приятный бонус, это все очень быстро работает :)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Ну и в конце - код который я написал что-бы "поиграться" с этой библиотекой, может кому нибудь пригодится:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; font-family: Consolas; font-size: 15px;"&gt;&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System.Collections.Generic;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System.Linq;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System.Threading;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System.Diagnostics;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;System.Collections.Concurrent;
&lt;span style="font-weight: bold;"&gt;using&lt;/span&gt;&amp;nbsp;Disruptor;
 
&lt;span style="font-weight: bold;"&gt;namespace&lt;/span&gt;&amp;nbsp;QueueTest
{
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;
	{
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;Value&amp;nbsp;{&amp;nbsp;&lt;span style="font-weight: bold;"&gt;get&lt;/span&gt;;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;set&lt;/span&gt;;&amp;nbsp;}
	}
 
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IBatchHandler&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;
	{
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnAvailable(&lt;span style="font-weight: bold;"&gt;long&lt;/span&gt;&amp;nbsp;sequence,&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data)&amp;nbsp;{
			data.Value++;
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnEndOfBatch()&amp;nbsp;{
		}
	}
 
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Decrementer&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IBatchHandler&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;
	{
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnAvailable(&lt;span style="font-weight: bold;"&gt;long&lt;/span&gt;&amp;nbsp;sequence,&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data)&amp;nbsp;{
			data.Value--;
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnEndOfBatch()&amp;nbsp;{
		}
	}
 
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueProducer&lt;/span&gt;
	{
		&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;count;
		&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IProducerBarrier&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;&amp;nbsp;barrier;
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;ValueProducer(&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;num,&amp;nbsp;&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IProducerBarrier&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;&amp;nbsp;pbarrier)&amp;nbsp;{
			count&amp;nbsp;=&amp;nbsp;num;
			barrier&amp;nbsp;=&amp;nbsp;pbarrier;
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;Run()&amp;nbsp;{
			&lt;span style="font-weight: bold;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;count;&amp;nbsp;i++)&amp;nbsp;{
				&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data;
				&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;seq&amp;nbsp;=&amp;nbsp;barrier.NextEntry(&lt;span style="font-weight: bold;"&gt;out&lt;/span&gt;&amp;nbsp;data);
				data.Value&amp;nbsp;=&amp;nbsp;i;
				barrier.Commit(seq);
			}
		}
	}
 
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueConsumer&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #5c5c5c; font-weight: bold;"&gt;IBatchHandler&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;
	{
		&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;iter&amp;nbsp;=&amp;nbsp;0;
		&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;count;
		&lt;span style="color: #484848; font-weight: bold;"&gt;AutoResetEvent&lt;/span&gt;&amp;nbsp;evt;
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;ValueConsumer(&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;cnt)&amp;nbsp;{
			count&amp;nbsp;=&amp;nbsp;cnt;
			evt&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;AutoResetEvent&lt;/span&gt;(&lt;span style="font-weight: bold;"&gt;false&lt;/span&gt;);
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnAvailable(&lt;span style="font-weight: bold;"&gt;long&lt;/span&gt;&amp;nbsp;sequence,&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;nbsp;data)&amp;nbsp;{
			&lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;&amp;nbsp;(sequence&amp;nbsp;==&amp;nbsp;count&amp;nbsp;-&amp;nbsp;1)
				evt.Set();
			&lt;span style="font-weight: bold;"&gt;if&lt;/span&gt;&amp;nbsp;(data.Value&amp;nbsp;!=&amp;nbsp;sequence&amp;nbsp;+&amp;nbsp;1)
				&lt;span style="color: #484848; font-weight: bold;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #676767;"&gt;"Error&amp;nbsp;at&amp;nbsp;{0}"&lt;/span&gt;,&amp;nbsp;iter&amp;nbsp;-&amp;nbsp;1);
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;OnEndOfBatch()&amp;nbsp;{
		}
 
		&lt;span style="font-weight: bold;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;WaitForAll()&amp;nbsp;{
			evt.WaitOne();
		}
	}
 
	&lt;span style="font-weight: bold;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Program&lt;/span&gt;
	{
		&lt;span style="font-weight: bold;"&gt;const&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;int&lt;/span&gt;&amp;nbsp;COUNT&amp;nbsp;=&amp;nbsp;100&amp;nbsp;*&amp;nbsp;1000;
		&lt;span style="font-weight: bold;"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;void&lt;/span&gt;&amp;nbsp;Main(&lt;span style="font-weight: bold;"&gt;string&lt;/span&gt;[]&amp;nbsp;args)&amp;nbsp;{
			&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;ringBuffer&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;RingBuffer&lt;/span&gt;&amp;lt;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;&amp;gt;(
				()&amp;nbsp;=&amp;gt;&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueEntry&lt;/span&gt;(),
				100&amp;nbsp;*&amp;nbsp;1024,
				&lt;span style="color: #484848; font-weight: bold;"&gt;ClaimStrategyFactory&lt;/span&gt;.&lt;span style="color: #555555; font-weight: bold;"&gt;ClaimStrategyOption&lt;/span&gt;.SingleThreaded,
				&lt;span style="color: #484848; font-weight: bold;"&gt;WaitStrategyFactory&lt;/span&gt;.&lt;span style="color: #555555; font-weight: bold;"&gt;WaitStrategyOption&lt;/span&gt;.Yielding);
 
			&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;cons&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueConsumer&lt;/span&gt;(COUNT);
			ringBuffer
				.ConsumeWith(&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;())
				.Then(&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Incrementer&lt;/span&gt;(),&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Decrementer&lt;/span&gt;())
				.Then(cons);
			&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;pbarrier&amp;nbsp;=&amp;nbsp;ringBuffer.CreateProducerBarrier();
			&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;prod&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;ValueProducer&lt;/span&gt;(COUNT,&amp;nbsp;pbarrier);
			ringBuffer.StartConsumers();
			&lt;span style="font-weight: bold;"&gt;var&lt;/span&gt;&amp;nbsp;sw&amp;nbsp;=&amp;nbsp;&lt;span style="font-weight: bold;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #484848; font-weight: bold;"&gt;Stopwatch&lt;/span&gt;();
			sw.Start();
			prod.Run();
			cons.WaitForAll();
			sw.Stop();
			&lt;span style="color: #484848; font-weight: bold;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #676767;"&gt;"Disruptor:&amp;nbsp;{0}ms"&lt;/span&gt;,&amp;nbsp;sw.ElapsedMilliseconds);
		}
	}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2458403310601998777?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/rgbn9tjqxWQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/rgbn9tjqxWQ/disruptor.html</link><author>noreply@blogger.com (Евгений Лазин)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-BtXLpe2OfDI/Toh_6VRuhoI/AAAAAAAAYu4/RByuAfGcnM0/s72-c/paint+%25287%2529.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/10/disruptor.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-3359606576096584418</guid><pubDate>Sun, 02 Oct 2011 14:58:00 +0000</pubDate><atom:updated>2011-10-02T20:16:48.613+04:00</atom:updated><title>Очереди сообщений</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Я хотел написать пост о библиотеке disruptor, начал писать введение и, совершенно случайно, написал целый пост :)&lt;br /&gt;
Итак, очереди бывают разными, бывают очереди, с помощью которых реализуют обход графа в ширину, а бывают такие очереди, с помощью которых можно передавать сообщения от одного потока к другому, этот пост именно о них.&lt;br /&gt;
Для начала договоримся, что очередь, это структура данных, поддерживающая две операции - enqueue и dequeue, добавление и извлечение элемента данных из очереди. Элементы извлекаются из очереди в FIFO порядке.&lt;br /&gt;
Когда речь заходит о распараллеливании каких либо вычислений, то многим на ум сразу приходит параллелизм на уровне данных, то бишь одну половину массива мы обрабатываем в одном потоке, а вторую в другом, в простейшем случае. Либо как нибудь еще разбиваем задачу на независимые части, обрабатываем их на разных процессорах и затем объединяем результаты.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Однако это возможно не всегда, некоторые вычисления представляют собой набор последовательных операций, в этом случае, мы не можем обрабатывать один элемент данных параллельно. Но, если нам нужно выполнять обработку множества последовательных элементов данных, то можно использовать &lt;a href="http://en.wikipedia.org/wiki/Pipeline_(software)"&gt;принцип конвейера&lt;/a&gt;. Мы выполняем обработку первого элемента данных на первом процессоре, затем продолжаем обработку на втором процессоре, затем на третьем и тд. При этом, когда мы выполняем, первый этап обработки для одного сообщения, мы можем выполнять второй этап обработки предыдущего и третий этап обработки пред-предыдущего сообщений и тд.,&amp;nbsp;&lt;u&gt;параллельно&lt;/u&gt;.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/--fiE_xWBRkQ/Tog115DPsFI/AAAAAAAAYus/Wa25MZY_GOQ/s1600/paint+%25283%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/--fiE_xWBRkQ/Tog115DPsFI/AAAAAAAAYus/Wa25MZY_GOQ/s320/paint+%25283%2529.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
В итоге, мы сможем одновременно обрабатывать столько сообщений, сколько у нас есть независимых операций.&lt;br /&gt;
В жизни все несколько сложнее, операции выполняются с разной скоростью, поэтому, для объединения разных этапов обработки в цепочку используются очереди. Мы кладем сообщение в первую очередь, поток, выполняющий первый этап обработки вытаскивает его оттуда, выполняет обработку и кладет результат в свою выходную очередь сообщений, которая в то же время, является входной для второго этапа обработки. И так далее.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-EhCv94p7ixs/Toa9T5rEqdI/AAAAAAAAYuc/DlC1LaTQLCA/s1600/paint+%25281%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://1.bp.blogspot.com/-EhCv94p7ixs/Toa9T5rEqdI/AAAAAAAAYuc/DlC1LaTQLCA/s400/paint+%25281%2529.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Мы можем использовать на одном из этапов обработки несколько потоков, если эта операция требует больше вычислительных ресурсов. Для этого мы должны на стороне производителя в &lt;a href="http://ru.wikipedia.org/wiki/Round-robin_(%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC)"&gt;round-robin&lt;/a&gt; порядке выбрать очередь, в которую будем записывать, а на стороне потребителя, в том же самом порядке выбрать очередь из которой сообщение будет извлечено и помещено в следующую очередь(это если нам нужно сохранить порядок сообщений, если не нужно, то можно сделать проще). Для этого нам нужны два счетчика, изначально их значения должны быть равны, прежде чем добавлять элемент, мы вычисляем индекс очереди как i mod N, где i - значение счетчика, N - количество очередей, добавляем элемент - queues[i mod N].enqueue(X), после этого мы увеличиваем i на единицу.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-2dq7YVQTLW8/TohTL8bbJXI/AAAAAAAAYu0/_N1Ty8hIpvo/s1600/paint+%25286%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-2dq7YVQTLW8/TohTL8bbJXI/AAAAAAAAYu0/_N1Ty8hIpvo/s320/paint+%25286%2529.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
На стороне потребителя нужно извлечь последовательность элементов из множества очередей, алгоритм будет таким же, только вместо enqueue нужно вызвать dequeue.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Естественно, для решения этой задачи нельзя использовать std::queue, System.Collection.Generics.Queue, java.util.Queue или то, что есть в вашем любимом языке программирования. Эти структуры данных не потокобезопасны, доступ к ним придется синхронизировать, а это означает что два потока не смогут одновременно добавить и извлечь элемент из очереди.&lt;br /&gt;
Помимо этого, операции на стороне потребителя и производителя часто выполняются с разной скоростью, в случае, если производитель работает быстрее чем потребитель, достаточно долго, программа просто вылетит по OOM, так как в очередь будет помещено слишком много элементов.&lt;br /&gt;
Для решения всех этих проблем были созданы специальные очереди. Их можно классифицировать следующим образом: блокирующие - неблокирующие; ограниченные - неограниченные. Так же очереди классифицируют по уровню concurrency - single producer/single consumer(SPSC), single producer/multiple consumers(SPMC), multiple producers/single consumer(MPSC), multiple producers/multiple consumers(MPMC). При этом данные характеристики могут сочетаться произвольным образом, например single producer/multiple consumers очередь может быть ограниченной и неблокирующей одновременно.&lt;br /&gt;
&lt;br /&gt;
Блокирующая очередь, это очередь, операции над которой могут заблокировать вызывающий поток до тех пор, пока состояние очереди не изменится. Например, в случае ограниченной очереди, попытка добавления элемента(enqueue) в переполненную очередь может быть заблокирована до тех пор, пока какой либо другой поток не извлечет элемент и не освободит место для нового элемента. Попытка извлечения элемента из пустой блокирующей очереди так же может заблокировать вызывающий поток до тех пор, пока в очередь не будет добавлен элемент. Обычно, для блокирующей очереди реализуют способ сообщить потоку потребителю, извлекающему сообщения из очереди, что производитель уже завершил работу.&amp;nbsp;Данные свойства делают блокирующие очереди очень простым в использовании инструментом для организации совместной работы множества потоков.&lt;br /&gt;
Неблокирующие очереди, как правило просто возвращают признак того, была операция выполнена, или нет. Их преимущество, перед блокирующими очередями, состоит в том, что они могут быть реализованы без использования мьютексов, семафоров и прочих condintion variables, которые&amp;nbsp;обычно&amp;nbsp;применяются в блокирующих очередях для реализации ожидания.&lt;br /&gt;
&lt;br /&gt;
Очереди также отличаются по внутренней реализации, существуют очереди на основе массивов и на основе списков. Общее у этих реализаций то, что в каждом случае присутствуют два указателя, Tail и Head. Tail - указатель конца списка, к которому добавляются элементы, Head - указатель на начало списка, из которого извлекаются элементы.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-pGWJvWE8xmA/TohMqCCJBxI/AAAAAAAAYuw/PMS5RYCV2eo/s1600/paint+%25285%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://3.bp.blogspot.com/-pGWJvWE8xmA/TohMqCCJBxI/AAAAAAAAYuw/PMS5RYCV2eo/s400/paint+%25285%2529.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
Таким образом, для добавления и для извлечения элементов из очереди нужно изменить одну из этих переменных и прочитать обе. Так же, очевидно, что на основе массива нельзя построить неограниченную очередь(очередь, в которую можно добавить произвольное количество элементов). Однако, очередь, реализованная на основе списка может быть ограниченной, достаточно поддерживать счетчик элементов очереди. &lt;i&gt;Кстати, автор этого поста видел и гибридный вариант, очередь на основе списка, элементами которой являлись массивы фиксированного размера, это оптимизация, упрощающая жизнь сборщику мусора.&lt;/i&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
Теперь о типах очередей с точки зрения concurrency.&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
SPSC - самая простая и быстрая очередь, она может быть реализована вообще без использования атомарных&amp;nbsp;&lt;i&gt;(команды с префиксом lock, блокирующие шину памяти на время выполнения)&lt;/i&gt; операций, достаточно двух барьеров памяти. Мало того, операции enqueue и dequeue могут быть реализованы как wait free операции &lt;i&gt;(естественно, wait free гарантия здесь условна, так как в случае списка, нужно выделить память под новый элемент, в случае массива wait free&amp;nbsp;гарантия&amp;nbsp;может&amp;nbsp;выполняться&amp;nbsp;только тогда, когда есть место в массиве)&lt;/i&gt;.&lt;/div&gt;
SPMC &amp;nbsp;и MPSC очереди немного сложнее и медленнее, так как в данном случае несколько потоков могут бороться за head либо за tail указатели. По этой причине, данные очереди могут быть реализованы только с применением атомарных операций. Для такой&amp;nbsp;очереди&amp;nbsp;нужна как минимум одна &lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81_%D0%BE%D0%B1%D0%BC%D0%B5%D0%BD%D0%BE%D0%BC"&gt;CAS операция&lt;/a&gt;, с одной из сторон, для MPSC - со стороны производителя, для SPMC - со стороны потребителя.&lt;br /&gt;
MPMC - наиболее универсальная и наименее эффективная очередь. Она требует использования двух атомарных CAS операций, одной при добавлении элементов и одной при извлечении.&lt;br /&gt;
&lt;br /&gt;
Все эти качества нужно учитывать при проектировании системы, выполняющей конвейерную обработку данных. Конвейерная обработка, это своего рода размен, мы увеличиваем общую пропускную способность(количество сообщений в сек.), но уменьшаем латентность(время обработки отдельного сообщения), ведь теперь помимо обработки сообщения, к латентности добавится время выполнения операций добавления и извлечения из всех очередей на пути сообщения. Также, не стоит забывать о балансировке нагрузки, если один из этапов конвейера работает на порядок быстрее чем все остальные, то нет смысла выделять его в отдельный этап и наоборот, если один из этапов выполняется слишком медленно, возможно стоит его разделить на части, либо выполнять его параллельно.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-3359606576096584418?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/sg-DrOXTZ6I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/sg-DrOXTZ6I/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/--fiE_xWBRkQ/Tog115DPsFI/AAAAAAAAYus/Wa25MZY_GOQ/s72-c/paint+%25283%2529.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/10/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2386889255157652159</guid><pubDate>Wed, 03 Aug 2011 09:16:00 +0000</pubDate><atom:updated>2011-10-02T20:17:33.663+04:00</atom:updated><title /><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Мне часто доводилось встречать на разных форумах и блогах такое мнение - если вы пишете приложение, критичное к скорости выполнения, то виртуальные функции не для вас. Обычно, в таких случаях советуют применять статический полиморфизм или еще что-то подобное.&lt;br /&gt;
На самом деле, с косвенными вызовами в общем и с виртуальными функциями/методами в частности - все хорошо. Современные процессоры умеют предсказывать ветвления даже в случае непрямого вызова, это может свести на нет все накладные расходы, связанные с вызовом виртуальной функции.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;span class="fullpost"&gt;Проблема в другом. Часто, виртуальные функции используют следующим образом: создают массив/список указателей на базовый класс, обходят все элементы массива и вызывают виртуальный метод. Это приводит к тому, что количество L1 кэш промахов заметно увеличивается(виртуальный метод может быть переопределен и при каждом новом вызове процессор, в худшем случае, будет выполнять новый код). Помимо этого, такой подход уменьшает вероятность успешного предсказания ветвления.&lt;br /&gt;
Я написал небольшой тест, демонстрирующий эти эффекты. Сначала, в список добавляются все элементы одного класса, затем другого и тд. После этого, для каждого элемента списка вызывается виртуальный метод. На моей машине это происходит примерно за 300 миллисекунд. Далее, элементы списка перемешиваются случайным образом, что увеличивает время обхода списка с вызовом метода втрое! И в конце я вызываю, в точно таком же цикле, обычный, не виртуальный метод, который делает ровно тоже самое что и виртуальные методы. Это занимает все те же 300 миллисекунд.&amp;nbsp;Делайте выводы :)&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;pre style="background: white; color: black; font-family: Droid Sans Mono; font-size: 13;"&gt;&lt;span class="fullpost"&gt;&lt;span class="fullpost"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt;&amp;nbsp;System;
&lt;span style="color: blue;"&gt;using&lt;/span&gt;&amp;nbsp;System.Collections.Generic;
&lt;span style="color: blue;"&gt;using&lt;/span&gt;&amp;nbsp;System.Linq;
&lt;span style="color: blue;"&gt;using&lt;/span&gt;&amp;nbsp;System.Text;
&lt;span style="color: blue;"&gt;using&lt;/span&gt;&amp;nbsp;System.Diagnostics;
 
&lt;span style="color: blue;"&gt;namespace&lt;/span&gt;&amp;nbsp;L1CacheMissDemo
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Program&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Main(&lt;span style="color: blue;"&gt;string&lt;/span&gt;[]&amp;nbsp;args)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;lst&amp;nbsp;=&amp;nbsp;&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;&amp;gt;();
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;1000000;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived1&lt;/span&gt;());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;1000000;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived2&lt;/span&gt;());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;1000000;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived3&lt;/span&gt;());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;1000000;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived4&lt;/span&gt;());
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Stopwatch&lt;/span&gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;foreach&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span style="color: blue;"&gt;in&lt;/span&gt;&amp;nbsp;lst)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x.Process();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Stop();
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Case&amp;nbsp;1:&amp;nbsp;{0}"&lt;/span&gt;,&amp;nbsp;s.ElapsedMilliseconds);
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: grey;"&gt;//&amp;nbsp;shuffle&amp;nbsp;elements&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;r&amp;nbsp;=&amp;nbsp;&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Random&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Guid&lt;/span&gt;.NewGuid().GetHashCode());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;lst.Count;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;j&amp;nbsp;=&amp;nbsp;r.Next(i,&amp;nbsp;lst.Count);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;t&amp;nbsp;=&amp;nbsp;lst[i];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst[i]&amp;nbsp;=&amp;nbsp;lst[j];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst[j]&amp;nbsp;=&amp;nbsp;t;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Restart();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;foreach&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span style="color: blue;"&gt;in&lt;/span&gt;&amp;nbsp;lst)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x.Process();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Stop();
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Case&amp;nbsp;2:&amp;nbsp;{0}"&lt;/span&gt;,&amp;nbsp;s.ElapsedMilliseconds);
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;p&amp;nbsp;=&amp;nbsp;&lt;span style="color: blue;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Program&lt;/span&gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Restart();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;foreach&lt;/span&gt;(&lt;span style="color: blue;"&gt;var&lt;/span&gt;&amp;nbsp;_&amp;nbsp;&lt;span style="color: blue;"&gt;in&lt;/span&gt;&amp;nbsp;lst)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.Process();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.Stop();
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Case&amp;nbsp;3:&amp;nbsp;{0}"&lt;/span&gt;,&amp;nbsp;s.ElapsedMilliseconds);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;k&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;100;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;+=&amp;nbsp;i&amp;nbsp;*&amp;nbsp;i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;abstract&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;abstract&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived1&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;k&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;100;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;+=&amp;nbsp;i&amp;nbsp;*&amp;nbsp;i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived2&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;k&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;100;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;+=&amp;nbsp;i&amp;nbsp;*&amp;nbsp;i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived3&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;k&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;100;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;+=&amp;nbsp;i&amp;nbsp;*&amp;nbsp;i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
 
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Derived4&lt;/span&gt;&amp;nbsp;:&amp;nbsp;&lt;span style="color: #2b91af;"&gt;Base&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;Process()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;k&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: blue;"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;100;&amp;nbsp;i++)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;+=&amp;nbsp;i&amp;nbsp;*&amp;nbsp;i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2386889255157652159?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/P8twD8rgZYI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/P8twD8rgZYI/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/08/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2066627389639176489</guid><pubDate>Sun, 19 Jun 2011 10:18:00 +0000</pubDate><atom:updated>2011-06-19T14:18:42.914+04:00</atom:updated><title /><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Чтение чужого кода - весьма полезное занятие, можно узнать много интересного, хотя все конечно зависит от того, кем этот код написан. В этом плане, код создателя Clojure -&amp;nbsp;&lt;a href="http://ru.wikipedia.org/wiki/%D0%A5%D0%B8%D0%BA%D0%BA%D0%B8,_%D0%A0%D0%B8%D1%87%D0%B0%D1%80%D0%B4"&gt;Ричарда Хикки&lt;/a&gt;,&amp;nbsp;просто эльдорадо какое-то :)&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;Вот один интересный прием использованный в Clojure - допустим у нас есть объект - массив фиксированной длины содержащий до 32-х элементов. Массив заполнен не полностью, некоторые элементы равны null, некоторые содержат полезные данные. Доступ к элементам осуществляется обычным образом, по индексу.&lt;/div&gt;&lt;div&gt;Ход мыслей обычного программиста - массив небольшой, поэтому можно просто создавать его полностью, часть элементов массива будут раны null, часть заняты полезными данными, код будет проще и будет быстрее работать, так как не нужно вычислять индекс элемента в массиве. Однако Ричард Хикки решил иначе, дело в том, что этот массив - часть &lt;a href="http://en.wikipedia.org/wiki/Persistent_data_structure"&gt;персистентной структуры данных&lt;/a&gt;, поэтому создавать массив полностью накладно, так как такие массивы будут создаваться очень часто в процессе, называемом path copying.&amp;nbsp;&lt;/div&gt;&lt;div&gt;Вот как это сделано в clojure - объект содержит массив и маску (32 бита). Массив содержит только полезные данные, то есть, если в массиве 4 элемента, и 28 null-ов, то будет создан массив из 4-х элементов. Маска служит индексом, если i-й элемент массива равен null, то i-й бит маски будет сброшен, а в противном случае - установлен.&lt;/div&gt;&lt;div&gt;Самое интересное в этом - поиск элемента в массиве по индексу. Допусти мы хотим получить значение i-го элемента массива. Для этого, нам нужно выполнить сравнение:&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;int bit = 1 &amp;lt;&amp;lt; i;&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;if (mask &amp;amp; bit == 0) return null;&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;в противном случае, элемент не равен null и нам нужно найти его смещение в массиве. Допустим, array - наш массив, он имеет размер - от 0 до &amp;nbsp;32х. Для получения индекса i-го элемента в массиве, мы должны выполнить следующие операции:&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;int index = numberOfSetBits(mask &amp;amp; (bit - 1));&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;return array[index];&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;где numberOfSetBits - функция, возвращающая количество не нулевых битов числа. Это вычисляется за несколько тактов процессора :)&lt;br /&gt;
Представим, что у нас есть массив из 4-х элементов. Допустим, 0-й, 3-й, 6-й и 7-й элементы не равны null. В этом случае, маска будет выглядеть так - 11001001. Младший бит&amp;nbsp;соответствует&amp;nbsp;первому элементу массива, а старший - последнему. Теперь, вычислим индекс последнего элемента массива - i = 7, bit = 1 &amp;lt;&amp;lt; 7 = 10000000. Поскольку bit - степень двойки, то bit - 1 будет равно 1111111. Если мы побитово сравним это значение с маской, то мы получим все те же биты, что и в маске, кроме старшего - 11001001 &amp;amp; 1111111 = 1001001. Теперь, если мы посчитаем биты в этом числе, то получим число не null элементов индекс которых меньше нашего i, а именно 3. Именно это число и будет индексом в нашем массиве, не включающем null значения.&lt;br /&gt;
Все эти битовые операции выполняются за считанные такты процессора и код в целом работает быстрее. Вообще, мне очень нравятся такие&amp;nbsp;не очевидные&amp;nbsp;решения :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2066627389639176489?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/vKfCp36SKeE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/vKfCp36SKeE/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/06/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-4017756322795044557</guid><pubDate>Sun, 29 May 2011 09:14:00 +0000</pubDate><atom:updated>2011-05-29T13:14:48.957+04:00</atom:updated><title>Рукибыпоотрывал пост</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Решил я сегодня попробовать Apache Etch. Это такая штука, которая позволяет описать набор сервисов и сообщений, на специальном IDL, скомпилировать это все специальным компилятором, получив на выходе набор исходников, добавить их в свой проект и наслаждаться жизнью. Этот проект привлек меня тем, что он более функциональный, нежели Thrift, позволяет делать больше. В частности, наследовать сообщения. Ну и Cisco тоже внушает некоторое доверие.&lt;div&gt;Так вот, у меня не заработал простой hello world, который я взял с официального сайта. Не заработал он вот из-за чего:&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-8G0hTj0g-HI/TeIM9jyETtI/AAAAAAAABfU/H-JtGLOS2Rc/s1600/etch_fail.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-8G0hTj0g-HI/TeIM9jyETtI/AAAAAAAABfU/H-JtGLOS2Rc/s1600/etch_fail.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Дело в том, что сообщения об ошибках зависят от локализации, а разработчик Etch использует эти сообщения не для отображения, он строит на них логику! За это нужно отрывать руки по самый локоть, ибо даже в MSDN сказано что так делать нельзя.&amp;nbsp;&lt;/div&gt;&lt;div&gt;В общем, до свиданья apache etch :D&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-4017756322795044557?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/SzprX0qh2eo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/SzprX0qh2eo/blog-post_29.html</link><author>noreply@blogger.com (Евгений Лазин)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-8G0hTj0g-HI/TeIM9jyETtI/AAAAAAAABfU/H-JtGLOS2Rc/s72-c/etch_fail.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/05/blog-post_29.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-4215435477143102235</guid><pubDate>Mon, 09 May 2011 10:14:00 +0000</pubDate><atom:updated>2011-05-09T14:19:52.035+04:00</atom:updated><title>В интернете кто-то снова не прав!</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Точнее, в оплоте создателей стартапов и специалистов по натягиванию шаблонов на wordpress - хабрахабре :)&lt;/span&gt;&lt;span class="fullpost"&gt;&lt;/span&gt;

&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Некий юзер, взялся переводить статьи о lock-free алгоритмах на великий и могучий, за что ему спасибо конечно. Но к несчастью для себя, он покусился на святое! По своему перевел термин lock-free на русский язык! Идея, на мой взгляд, крайне неудачная, особенно в свете того, что уже давно прижился перевод - "без блокировок".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Почему lock-free неправильно переводить как "беззамочный"? Все очень просто, в информатике нет "замков", зато есть блокировки. Здесь даже говорить не о чем.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Немного сложнее с "беззахватными" алгоритмами. Под захватом подразумевается захват некоего ресурса, например мьютекса, то есть определенную семантику. Lock-free алгоритм, конечно же не может ничего захватывать.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Гарантия lock-freredom означает, что в каждый момент времени, один из потоков совершает прогресс. Полезным на практике следствием соблюдения lock-freredom гарантии является то, что мы можем прибить любой из потоков, выполняющих наш lock-free алгоритм и у нас гарантированно не возникнет dead-lock. Если гарантия lock-freedom не соблюдается, то один из потоков может сделать нечто такое, что заставит другие потоки его ждать. Например, захватить мьютекс. Если мы этот поток прибьем, то возникнет dead-lock.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Так вот, гарантия lock-freedom может не соблюдаться даже при полном отсутствии мьютексов, критических секций и любых других объектов, имеющих такую семантику. Например, приложение может не использовать общие для нескольких потоков данные вообще, посылая, вместо этого сообщения. При этом, взаимная блокировка возникнуть очень даже может. Поток, по каким-то причинам(например, из-за того, что его убили), может не посылать сообщение другому потоку, который это сообщение ждет.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Поэтому, я считаю термин "беззахватный" крайне неудачным, не отражающим сути.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;

&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;P.S.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Я несколько раз написал о том, что поток может быть "прибит". В Windows это может быть сделано функцией TerminateThread, например. Так вот, прибивать потоки, не в коем случае не нужно. Это может привести к непредсказуемым последствиям. Если вы используете эту функцию, то у меня для вас плохие новости!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;За все время работы, мне лишь однажды пришлось столкнуться с этой проблемой. Я написал библиотеку, клиент которой часто вызывал TerminateThread. Это иногда приводило к неприятным последствиям. Поэтому, мне пришлось предоставить этому клиенту lock-free интерфейс.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-4215435477143102235?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/xLRvje0QLvU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/xLRvje0QLvU/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/05/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2966872092019547685</guid><pubDate>Tue, 26 Apr 2011 18:57:00 +0000</pubDate><atom:updated>2011-04-26T22:57:33.627+04:00</atom:updated><title>GC и латентность</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/--fKDz5qGwS0/TbcR2YfAPJI/AAAAAAAABeM/Ql4rV5KIPIg/s1600/latency.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/--fKDz5qGwS0/TbcR2YfAPJI/AAAAAAAABeM/Ql4rV5KIPIg/s1600/latency.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Пояснение. Это скриншот тестовой утилиты, которая измеряет производительность одного нашего продукта (работающего под .NET Framework 4). По оси абсцисс - номер запроса, по оси ординат - время получения ответа на запрос. Запросы не отличаются друг от друга. В среднем, один запрос выполняется меньше чем за 5&amp;nbsp;миллисекунд. Но один, выполняется в 50 раз медленнее. Это происходит из-за того, что &amp;nbsp;выполнение запроса приостанавливается для того, что-бы сборщик мусора смог сделать свою работу.&lt;/div&gt;&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2966872092019547685?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/eR8ysYCJNbE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/eR8ysYCJNbE/gc.html</link><author>noreply@blogger.com (Евгений Лазин)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/--fKDz5qGwS0/TbcR2YfAPJI/AAAAAAAABeM/Ql4rV5KIPIg/s72-c/latency.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/04/gc.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-8689641518965929317</guid><pubDate>Sat, 16 Apr 2011 13:28:00 +0000</pubDate><atom:updated>2011-04-16T17:40:44.531+04:00</atom:updated><title /><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Прочитал вчера вот эту статью: &lt;a href="http://easy-coding.blogspot.com/2011/04/go.html"&gt;http://easy-coding.blogspot.com/2011/04/go.html&lt;/a&gt;  &lt;br /&gt;
&lt;blockquote&gt;Итак: данная программа берет TAR с исходниками, распаковывает его, и каждый файл прогоняет через компилятор.  Сразу скажу, цель того, что я все это пишу тут, это продемонстрировать (и не более того), как просто и удобно на Go можно писать многопоточные императивные программы.&lt;/blockquote&gt;и не впечатлился. Эта программа реализует простую вещь - Master/Worker pattern. Каких-либо особых преимуществ языка Go в этом нелегком деле я не заметил. Для написания этой программы, язык программирования вообще не важен, он должен позволять запускать потоки и использовать блокирующие очереди, вот и все. Все тоже самое может быть написано на C++, с использованием класса tbb::concurrent_queue, или на C#, с использованием класса BlockingCollection. Код будет выглядеть так же просто.&lt;br /&gt;
Мало того, на шарпе, можно написать как-то так:&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;using&lt;/span&gt;(&lt;span class="Apple-style-span" style="color: blue;"&gt;var &lt;/span&gt;tar = &lt;span class="Apple-style-span" style="color: blue;"&gt;new &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #990000;"&gt;TarReader&lt;/span&gt;(tarname))&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="Apple-style-span" style="color: blue;"&gt;var &lt;/span&gt;files = tar.NewReader(tmpdir); &lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: #990000;"&gt;&amp;nbsp; &amp;nbsp; Parallel&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;.ForEach(files, file =&amp;gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;Compiler&lt;/span&gt;.Run(file, params));&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
(далее, имена всех классов и методов вымышлены, все совпадения - случайны)&lt;br /&gt;
&amp;nbsp;Допустим, tar - объект, читающий tar архив, метод NewReader(tmpdir) - возвращает IEnumerable&lt;string&gt;, при обходе которого на диске, в каталоге tmpdir, будут создаваться новые файлы, а итератор будет возвращать их имена. При вызове tar.Dispose() - все временные файлы должны быть удалены.&lt;/string&gt;&lt;/div&gt;&lt;div&gt;Допустим, у нас есть класс Compiler, со статическим методом Run, который получает имя файла и набор флагов, в виде строк, запускает компилятор, дожидается когда он отработает и завершает работу. &lt;/div&gt;&lt;div&gt;Вот собственно и все. TPL не будет создавать 100500 потоков, количество выполняемых параллельно задач будет зависеть от количества процессоров. Возиться с очередями и балансировкой нагрузки - не нужно. Обработка ошибок - проще некуда.&lt;/div&gt;&lt;div&gt;Возникает логичный вопрос - зачем этот Go вообще нужен? :)&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-8689641518965929317?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/GVCMXBoOX8E" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/GVCMXBoOX8E/httpeasy-coding.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>7</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/04/httpeasy-coding.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-652574321409311390</guid><pubDate>Tue, 04 Jan 2011 15:42:00 +0000</pubDate><atom:updated>2011-10-01T10:41:17.164+04:00</atom:updated><title /><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div style="background-color: transparent; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
&lt;span style="white-space: pre-wrap;"&gt;Вдогонку к предыдущему посту. Мы всегда, неосознанно, ищем во всем связи, даже если никакой связи на самом деле нет. Проявляется это по разному, например, многие хоккеисты во время плей-офф не бреются, а тренеры не меняют рубашки :)
Программисты в этом деле - впереди планеты всей, ведь у нас есть специальный инструмент для внесения в код подобных заблуждений - наследование! Если между сущностями есть связь - то их можно объединить в иерархию наследования.
Пожалуй, самый яркий пример подобного заблуждения встречается в литературе, в качестве примера объектно ориентированного программирования - иерархия фигур в векторном графическом редакторе, знаменитый Shape и его наследники - Line, Rectangle и прочие. (Справедливости ради стоит отметить, что автор этих строк, когда-то давно, написал простой векторный граф. редактор используя именно такой подход :D)
Итак, у нас есть базовый абстрактный класс - Shape, у которого есть набор виртуальных методов для: вывода себя на экран/графический контекст; получения bounding box-а объекта; трансформации объекта... Далее, программист должен реализовать классы - наследники Shape, которые специализируют все операции для определенной фигуры.
Плюсы этого подхода - кажущаяся простота кода, вроде все в одном месте, а также повторное использование кода, к примеру, класс Circle может быть наследником класса Ellipse. Минусы несколько менее очевидны: сложность внесения изменений - на каждую новую фигуру нам потребуется реализовать новый класс - наследник Shape и реализовать соответствующие вирт. методы, а если мы хотим добавить новую операцию, для которой нужен еще один вирт. метод, то нам придется реализовать его для каждого существующего класса - наследника Shape; не очень хорошая производительность - у нас целых два уровня косвенности - указатель на объект и виртуальный метод этого объекта. И самый главный недостаток этого подхода - нам не нужно знать о том, что та или иная фигура является окружностью или линией, это не имеет значения, так зачем же нам поддерживать иерархию наследования?
Иногда самый простой и очевидный способ решения проблемы - самый правильный. Однако, в данном случае, наиболее простой и эффективный метод решения достаточно не очевиден и даже контр-интуитивен. Представим, что у нас есть два массива - массив точек и массив метаданных. Массив точек содержит координаты всех точек чертежа: начало и конец каждой линии; начало, конец и контрольные точки каждого спалйна, точки заливки... Массив метаданных должен содержать информацию о том, к чему относится та или иная точка, а также прочую информацию об объекте: начало линии, конец линии, начало сплайна, конец сплайна, изменить цвет линии, изменить цвет заливки и тд. В этом случае, для того, что-бы отобразить все на экране, нам потребуются два индекса/указателя на текущую позицию в каждом из массивов, далее, в цикле мы будем выбирать поочередно метаданные и соответствующие им точки. К примеру, если в текущей позиции массива метаданных находится команда LINE, то, начиная с текущей позиции массива точек, должны быть выбраны две точки - координаты начала и конца линии и, используя текущий цвет фигуры, нарисована линия; если мы встретили в метаданных команду FLOOD_FILL, то из массива точек следует выбрать одну точку и выполнить заливку текущим цветом фона из этой точки.
Минусы этого подхода - ну очень непонятно для поклонников GoF, Грэди Буча и Скотта Мейерса. Плюсы: очень легко изменять код - набор изначальных примитивов очень ограничен и не меняется, операции реализуются для примитивов, не для фигур, один раз; эффективность - нет никаких указателей, смарт-поинтеров, виртуальных методов, многие операции могут быть реализованы очень просто, например, для поворота всего чертежа, достаточно умножить каждую точку массива на соответствующую матрицу поворота.
Конечно, это не означает, что наследование это плохо, или, что следует отказаться от ООП, просто следует помнить о том, что то, что у вас в голове выстраивается в иерархию, на самом деле иерархией может и не быть. Фигуры чертежа состоят из примитивов - линий, сплайнов. То, что из этих линий и сплайнов можно создать более сложные фигуры, которые могут быть объединены в иерархию - может быть совсем не важно для решения задачи.&lt;/span&gt;&lt;/div&gt;
&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-652574321409311390?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/exTqEPSyg78" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/exTqEPSyg78/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>6</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2011/01/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2787080538356365986</guid><pubDate>Sun, 05 Dec 2010 20:20:00 +0000</pubDate><atom:updated>2010-12-05T23:20:29.265+03:00</atom:updated><title /><description>Я считаю, что люди - иррациональные существа, логика для нас - противоестественна, а рациональному мышлению нужно учиться всю жизнь. На наши решения, очень сильно влияют различные&amp;nbsp;&lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B3%D0%BD%D0%B8%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D1%85_%D0%B8%D1%81%D0%BA%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9"&gt;когнитивные искажения&lt;/a&gt;. Одно из самых сильных, на мой взгляд - склонность искать подтверждение собственной правоты, вместо того, что-бы рассматривать альтернативы. Любой, особенно неопытный, программист - делает это постоянно. Вместо того, что-бы думать о том, чем плох наш код, искать его недостатки, мы ищем его достоинства и, естественно, находим. Позднее, с недостатками мы все же встречаемся, в процессе тестирования и отладки :)&lt;span class="fullpost"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2787080538356365986?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/kX_Ui42LT00" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/kX_Ui42LT00/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>6</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/12/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-4181481255609477830</guid><pubDate>Sun, 18 Jul 2010 06:48:00 +0000</pubDate><atom:updated>2010-07-18T10:48:23.545+04:00</atom:updated><title /><description>&lt;p&gt;Увидел сегодня следующее:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.reddit.com/r/programming/comments/cqn6o/whats_wrong_with_c_from_the_point_of_view_of/c0ui1dw" target="_blank"&gt;Everyone should program in C++ for a few years so they learn memory management, project compilation strategies, decoupling, and a host of other professional activities that are needed to program in C++. But when they go back to the more convenient languages they will realize how much they enjoy programming again. &lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Я в общем-то тоже считаю, что умение программировать на С++ – очень полезный навык. Рано или поздно, C++ программист учится очень рациональному и прагматичному подходу к программированию, или терпит фиаско :)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-4181481255609477830?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/cBiy8CJBH_s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/cBiy8CJBH_s/everyone-should-program-in-c-for-few.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>2</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/07/everyone-should-program-in-c-for-few.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-2476875361950487146</guid><pubDate>Thu, 15 Jul 2010 19:45:00 +0000</pubDate><atom:updated>2010-07-15T23:45:01.623+04:00</atom:updated><title>Veracity – DVCS по новому.</title><description>&lt;p&gt;Вчера произошло интересное событие, которое почему-то обошли вниманием в блогах. &lt;a href="http://www.ericsink.com/about_author.html" target="_blank"&gt;Эрик Синк&lt;/a&gt; (надеюсь я правильно пишу его имя), представил на конференции OSCON новую распределенную систему версионного контроля – Veracity. Она пока еще очень alpha и очень preview, но выглядит - очень интересно и многообещающе. &lt;/p&gt;  &lt;p&gt;Для начала, небольшая предыстория. Главная фишка любой современной DVCS – хранение истории изменений в виде ненаправленного ацикличного графа (к слову, об этом хорошо написано в блоге автора – &lt;a href="http://software.ericsink.com/entries/dvcs_dag_1.html" target="_blank"&gt;здесь&lt;/a&gt; и &lt;a href="http://software.ericsink.com/entries/dvcs_dag_2.html" target="_blank"&gt;здесь&lt;/a&gt;). Это именно то, что делает таким простым процесс слияния, так как мы сливаем не рабочую копию и содержимое репозитория, как в SVN. Вместо этого мы merge-им содержимое двух changeset-ов(попросту говоря – двух разных наборов изменений, сделанных разными людьми). При этом информация о слиянии остается в репозитории и мы можем все повторить, если что-то пошло не так. Помимо этого, подобный способ хранения истории, позволяет сделать версионный контроль распределенным. Мы, пользователи DVCS – не имеем дела с версиями файлов, мы просто обмениваемся изменениями между собой, это очень круто :)&lt;/p&gt;  &lt;p&gt;Однако, у медали есть и обратная сторона. Распределенные системы версионного контроля, такие как&amp;#160; git, bazar и mercurial, при том, что они замечательно справляются со своей основной задачей – управлением изменениями, все же имеют один серьезный недостаток. Все существующие инструменты разработки -&amp;#160; bug/issue/work item трэкеры и тому подобное - ориентированы на работу с линейной историей изменений. В результате, получается несколько странная картина – мы имеем распределенную историю изменений и.. централизованные wiki и bug трэкер. Разработчик может жить в распределенном мире ровно до тех пор, пока ему не потребуется как либо взаимодействовать со своими коллегами.&lt;/p&gt;  &lt;p&gt;Теперь к делу. Господин Sink, &lt;a href="http://www.ericsink.com/entries/veracity_early.html" target="_blank"&gt;анонсировал&lt;/a&gt; новую, распределенную систему управления версиями Veracity. Среди множества заявленных возможностей есть одна очень интересная – распределенная база данных. Это позволит хранить в истории изменений различную структурированную информацию, например, информацию о багах. Потенциально, это может привести к появлению таких вещей, как децентрализованный bug tracking. Выглядеть он может примерно так: вы работаете с коллегой Васей над одним проектом, при этом, у вас, в bug tracker-е заведено несколько багов. Пока вы занимаетесь реализацией какой-либо фичи, Вася работает над устранением одного из этих мерзких багов, чинит его, отдает тестировщикам, тестировщики закрывают баг, при этом в вашем репозитории, информации об этом нет, баг все еще открыт и воспроизводится, так как там еще нет и Васиных изменений, которые этот баг чинят. Спустя какое-то время, вы забираете изменения, сделанные Васей и сливаете со своими, после чего, обнаруживаете, что баг находится в закрытом состоянии и не воспроизводится, после чего всем становится хорошо :)&lt;/p&gt;  &lt;p&gt;Особенно радует тот факт, что Veracity разрабатывается не кучкой народных умельцев, а достаточно серьезной софтверной компанией, которая планирует зарабатывать не на самой DVCS, а на продуктах, построенных на ее основе.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-2476875361950487146?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/QJdle4a-skw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/QJdle4a-skw/veracity-dvcs.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>2</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/07/veracity-dvcs.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-7402812486923253294</guid><pubDate>Sun, 09 May 2010 10:16:00 +0000</pubDate><atom:updated>2010-05-09T16:23:48.897+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">fp</category><category domain="http://www.blogger.com/atom/ns#">fsharp</category><category domain="http://www.blogger.com/atom/ns#">codejam</category><title>Google code jam. Qualification Round 2010.</title><description>&lt;p&gt;Решил вчера поучаствовать в отборочном раунде code jam. Раунд состоял из трех достаточно простых задач, мне хватило терпения только на первые две, хотя как решать третью я тоже понял :)&lt;/p&gt;  &lt;p&gt;Первая задача, &lt;a href="http://code.google.com/codejam/contest/dashboard?c=433101#s=p0" target="_blank"&gt;snaper chain&lt;/a&gt; – самая простая, достаточно понять, что состояние snapper-ов в цепочке после K щелчков, будет эквивалентно двоичному представлению числа K. Вот мое решение на F#:&lt;/p&gt;  &lt;pre style="background: #ffffff; color: #000000"&gt;&lt;span style="color: #800000; font-weight: bold"&gt;open&lt;/span&gt; System
&lt;span style="color: #800000; font-weight: bold"&gt;open&lt;/span&gt; System&lt;span style="color: #008c00"&gt;.&lt;/span&gt;IO

&lt;span style="color: #808030"&gt;/&lt;/span&gt;&lt;span style="color: #808030"&gt;/&lt;/span&gt; read the input file
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; args &lt;span style="color: #808030"&gt;=&lt;/span&gt; Environment&lt;span style="color: #008c00"&gt;.&lt;/span&gt;GetCommandLineArgs&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputPath &lt;span style="color: #808030"&gt;=&lt;/span&gt; args.&lt;span style="color: #808030"&gt;[&lt;/span&gt;args&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Length &lt;span style="color: #808030"&gt;-&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;&lt;span style="color: #808030"&gt;]&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; outputPath &lt;span style="color: #808030"&gt;=&lt;/span&gt; Path&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ChangeExtension&lt;span style="color: #808030"&gt;(&lt;/span&gt;inputPath&lt;span style="color: #808030"&gt;,&lt;/span&gt; &lt;span style="color: #0000e6"&gt;&amp;quot;.out&amp;quot;&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputStr &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;new&lt;/span&gt; StreamReader&lt;span style="color: #808030"&gt;(&lt;/span&gt;inputPath&lt;span style="color: #808030"&gt;)&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; outputStr &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;new&lt;/span&gt; StreamWriter&lt;span style="color: #808030"&gt;(&lt;/span&gt;outputPath&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; testsNum &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt; &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;|&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ReadLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputSeq&lt;span style="color: #808030"&gt;:&lt;/span&gt;seq&lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt;&lt;span style="color: #808030"&gt;*&lt;/span&gt;&lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt;&lt;span style="color: #808030"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #808030"&gt;=&lt;/span&gt; seq &lt;span style="color: #808030"&gt;{&lt;/span&gt;
    &lt;span style="color: #800000; font-weight: bold"&gt;while&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;EndOfStream &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;false&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;do&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; line &lt;span style="color: #808030"&gt;=&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ReadLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; lst &lt;span style="color: #808030"&gt;=&lt;/span&gt; line&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Split&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6"&gt;' '&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
        yield &lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt; lst.&lt;span style="color: #808030"&gt;[&lt;/span&gt;&lt;span style="color: #008c00"&gt;0&lt;/span&gt;&lt;span style="color: #808030"&gt;]&lt;/span&gt;&lt;span style="color: #808030"&gt;,&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt; lst.&lt;span style="color: #808030"&gt;[&lt;/span&gt;&lt;span style="color: #008c00"&gt;1&lt;/span&gt;&lt;span style="color: #808030"&gt;]&lt;/span&gt;
    &lt;span style="color: #808030"&gt;}&lt;/span&gt;

&lt;span style="color: #808030"&gt;/&lt;/span&gt;&lt;span style="color: #808030"&gt;/&lt;/span&gt; write the output file
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; snapperState n k &lt;span style="color: #808030"&gt;=&lt;/span&gt;
    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; l &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #008c00"&gt;2&lt;/span&gt; &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt; n &lt;span style="color: #808030"&gt;-&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;
    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; m &lt;span style="color: #808030"&gt;=&lt;/span&gt; k % l
    &lt;span style="color: #800000; font-weight: bold"&gt;match&lt;/span&gt; l &lt;span style="color: #808030"&gt;-&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt; &lt;span style="color: #808030"&gt;=&lt;/span&gt; m &lt;span style="color: #800000; font-weight: bold"&gt;with&lt;/span&gt;
    &lt;span style="color: #808030"&gt;|&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;true&lt;/span&gt;  &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color: #0000e6"&gt;&amp;quot;ON&amp;quot;&lt;/span&gt;
    &lt;span style="color: #808030"&gt;|&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;false&lt;/span&gt; &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color: #0000e6"&gt;&amp;quot;OFF&amp;quot;&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;mutable&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;for&lt;/span&gt; n&lt;span style="color: #808030"&gt;,&lt;/span&gt; k &lt;span style="color: #800000; font-weight: bold"&gt;in&lt;/span&gt; inputSeq &lt;span style="color: #800000; font-weight: bold"&gt;do&lt;/span&gt;
    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; line &lt;span style="color: #808030"&gt;=&lt;/span&gt; sprintf &lt;span style="color: #0000e6"&gt;&amp;quot;Case #&lt;/span&gt;&lt;span style="color: #0f69ff"&gt;%d&lt;/span&gt;&lt;span style="color: #0000e6"&gt;: &lt;/span&gt;&lt;span style="color: #0f69ff"&gt;%s&lt;/span&gt;&lt;span style="color: #0000e6"&gt;&amp;quot;&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;|&lt;/span&gt; snapperState n k
    outputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;WriteLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;line&lt;span style="color: #808030"&gt;)&lt;/span&gt;
    caseIx &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;-&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;+&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;

outputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Close&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Close&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Вторая задача, &lt;a href="http://code.google.com/codejam/contest/dashboard?c=433101#s=p1" target="_blank"&gt;fair warning&lt;/a&gt; – намного сложнее. Суть задачи – в следующем, у нас есть набор чисел – t1, t2,.. tn. Нужно найти такое значение y, для которого справедливо условие – (Y + ti) mod T = 0, для любого i &amp;lt; n. Причем, T – должно быть максимально возможным. Помимо этого, исходные данные могут содержать большие числа, так и написано: &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;64 bits will not save you. You have been warned.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Я использовал следующий алгоритм – сначала массив чисел ti сортируется, затем – нормализуется (из каждого элемента вычитается значение минимального элемента); далее, вычисляется наибольший общий делитель элементов массива(функция gcdv), в результате чего мы получаем значение T, после чего достаточно легко рассчитать значение Y. Вот мое решение:&lt;/p&gt;

&lt;pre style="background: #ffffff; color: #000000"&gt;&lt;span style="color: #800000; font-weight: bold"&gt;open&lt;/span&gt; System
&lt;span style="color: #800000; font-weight: bold"&gt;open&lt;/span&gt; System&lt;span style="color: #008c00"&gt;.&lt;/span&gt;IO
&lt;span style="color: #800000; font-weight: bold"&gt;open&lt;/span&gt; System&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Numerics

&lt;span style="color: #808030"&gt;/&lt;/span&gt;&lt;span style="color: #808030"&gt;/&lt;/span&gt; read the input file
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; args &lt;span style="color: #808030"&gt;=&lt;/span&gt; Environment&lt;span style="color: #008c00"&gt;.&lt;/span&gt;GetCommandLineArgs&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputPath &lt;span style="color: #808030"&gt;=&lt;/span&gt; args.&lt;span style="color: #808030"&gt;[&lt;/span&gt;args&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Length &lt;span style="color: #808030"&gt;-&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;&lt;span style="color: #808030"&gt;]&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; outputPath &lt;span style="color: #808030"&gt;=&lt;/span&gt; Path&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ChangeExtension&lt;span style="color: #808030"&gt;(&lt;/span&gt;inputPath&lt;span style="color: #808030"&gt;,&lt;/span&gt; &lt;span style="color: #0000e6"&gt;&amp;quot;.out&amp;quot;&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputStr &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;new&lt;/span&gt; StreamReader&lt;span style="color: #808030"&gt;(&lt;/span&gt;inputPath&lt;span style="color: #808030"&gt;)&lt;/span&gt;
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; outputStr &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;new&lt;/span&gt; StreamWriter&lt;span style="color: #808030"&gt;(&lt;/span&gt;outputPath&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; testsNum &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;int&lt;/span&gt; &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;|&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ReadLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
printfn &lt;span style="color: #0000e6"&gt;&amp;quot;N: &lt;/span&gt;&lt;span style="color: #0f69ff"&gt;%d&lt;/span&gt;&lt;span style="color: #0000e6"&gt;&amp;quot;&lt;/span&gt; testsNum

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; inputSeq &lt;span style="color: #808030"&gt;=&lt;/span&gt; seq &lt;span style="color: #808030"&gt;{&lt;/span&gt;
    &lt;span style="color: #800000; font-weight: bold"&gt;while&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;EndOfStream &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;false&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;do&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; line &lt;span style="color: #808030"&gt;=&lt;/span&gt; inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ReadLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; strlst &lt;span style="color: #808030"&gt;=&lt;/span&gt; line&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Split&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6"&gt;' '&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;.&lt;span style="color: #808030"&gt;[&lt;/span&gt;&lt;span style="color: #008c00"&gt;1&lt;/span&gt;..&lt;span style="color: #808030"&gt;]&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; intlst &lt;span style="color: #808030"&gt;=&lt;/span&gt; Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;map &lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #800000; font-weight: bold"&gt;fun&lt;/span&gt; x &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; BigInteger&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Parse&lt;span style="color: #808030"&gt;(&lt;/span&gt;x&lt;span style="color: #808030"&gt;)&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt; strlst
        yield intlst
    &lt;span style="color: #808030"&gt;}&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; gcd a b &lt;span style="color: #808030"&gt;=&lt;/span&gt; BigInteger&lt;span style="color: #008c00"&gt;.&lt;/span&gt;GreatestCommonDivisor&lt;span style="color: #808030"&gt;(&lt;/span&gt;a&lt;span style="color: #808030"&gt;,&lt;/span&gt; b&lt;span style="color: #808030"&gt;)&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; gcdv vals &lt;span style="color: #808030"&gt;=&lt;/span&gt; Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;reduce gcd vals
            
&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; getDiff events &lt;span style="color: #808030"&gt;=&lt;/span&gt; 
    &lt;span style="color: #800000; font-weight: bold"&gt;if&lt;/span&gt; Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;length events &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color: #008c00"&gt;2&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;then&lt;/span&gt;
        failwith &lt;span style="color: #0000e6"&gt;&amp;quot;error in getDiff, events array is to small&amp;quot;&lt;/span&gt;
    Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;sortInPlace events
    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; min &lt;span style="color: #808030"&gt;=&lt;/span&gt; events.&lt;span style="color: #808030"&gt;[&lt;/span&gt;&lt;span style="color: #008c00"&gt;0&lt;/span&gt;&lt;span style="color: #808030"&gt;]&lt;/span&gt;
    min&lt;span style="color: #808030"&gt;,&lt;/span&gt; Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;map &lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #800000; font-weight: bold"&gt;fun&lt;/span&gt; x &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; x &lt;span style="color: #808030"&gt;-&lt;/span&gt; min&lt;span style="color: #808030"&gt;)&lt;/span&gt; events.&lt;span style="color: #808030"&gt;[&lt;/span&gt;&lt;span style="color: #008c00"&gt;1&lt;/span&gt;..&lt;span style="color: #808030"&gt;]&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; &lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;|&lt;/span&gt;Length&lt;span style="color: #808030"&gt;|&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt; arr &lt;span style="color: #808030"&gt;=&lt;/span&gt; Array&lt;span style="color: #008c00"&gt;.&lt;/span&gt;length arr

&lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; &lt;span style="color: #800000; font-weight: bold"&gt;mutable&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;=&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;

&lt;span style="color: #800000; font-weight: bold"&gt;for&lt;/span&gt; events &lt;span style="color: #800000; font-weight: bold"&gt;in&lt;/span&gt; inputSeq &lt;span style="color: #800000; font-weight: bold"&gt;do&lt;/span&gt;

    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; result &lt;span style="color: #808030"&gt;=&lt;/span&gt;
        &lt;span style="color: #800000; font-weight: bold"&gt;match&lt;/span&gt; events &lt;span style="color: #800000; font-weight: bold"&gt;with&lt;/span&gt;
        &lt;span style="color: #808030"&gt;|&lt;/span&gt; Length &lt;span style="color: #008c00"&gt;0&lt;/span&gt;
        &lt;span style="color: #808030"&gt;|&lt;/span&gt; Length &lt;span style="color: #008c00"&gt;1&lt;/span&gt; &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; 0I
        &lt;span style="color: #808030"&gt;|&lt;/span&gt; &lt;span style="color: #008c00"&gt;_&lt;/span&gt; &lt;span style="color: #808030"&gt;-&amp;gt;&lt;/span&gt; 
            &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; min&lt;span style="color: #808030"&gt;,&lt;/span&gt; diff &lt;span style="color: #808030"&gt;=&lt;/span&gt; getDiff events 
            &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; factor &lt;span style="color: #808030"&gt;=&lt;/span&gt; gcdv diff
            &lt;span style="color: #800000; font-weight: bold"&gt;if&lt;/span&gt; min % factor &lt;span style="color: #808030"&gt;=&lt;/span&gt; 0I &lt;span style="color: #800000; font-weight: bold"&gt;then&lt;/span&gt; 0I
            &lt;span style="color: #800000; font-weight: bold"&gt;else&lt;/span&gt; factor &lt;span style="color: #808030"&gt;-&lt;/span&gt; &lt;span style="color: #808030"&gt;(&lt;/span&gt;min % factor&lt;span style="color: #808030"&gt;)&lt;/span&gt;

    &lt;span style="color: #800000; font-weight: bold"&gt;let&lt;/span&gt; line &lt;span style="color: #808030"&gt;=&lt;/span&gt; sprintf &lt;span style="color: #0000e6"&gt;&amp;quot;Case #&lt;/span&gt;&lt;span style="color: #0f69ff"&gt;%d&lt;/span&gt;&lt;span style="color: #0000e6"&gt;: &lt;/span&gt;&lt;span style="color: #0f69ff"&gt;%s&lt;/span&gt;&lt;span style="color: #0000e6"&gt;&amp;quot;&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;|&lt;/span&gt; result&lt;span style="color: #008c00"&gt;.&lt;/span&gt;ToString&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
    outputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;WriteLine&lt;span style="color: #808030"&gt;(&lt;/span&gt;line&lt;span style="color: #808030"&gt;)&lt;/span&gt;
    caseIx &lt;span style="color: #808030"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #808030"&gt;-&lt;/span&gt; caseIx &lt;span style="color: #808030"&gt;+&lt;/span&gt; &lt;span style="color: #008c00"&gt;1&lt;/span&gt;

outputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Close&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;
inputStr&lt;span style="color: #008c00"&gt;.&lt;/span&gt;Close&lt;span style="color: #808030"&gt;(&lt;/span&gt;&lt;span style="color: #808030"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Кстати, сразу после начала раунда я обнаружил что на моем домашнем компьютере нет ни Visual Studio, ни интерпретатора python-a, даже несчастного с++ компиялтора нет. Вышел из положения скачав F# CTP, код набирал в vim. F# interpreter – очень удобная штука, я его использовал в интерактивном режиме, в качестве REPL, а так-же для запуска своей писанины :)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-7402812486923253294?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/-MJU365GR5E" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/-MJU365GR5E/google-code-jam-qualification-round.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>3</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/05/google-code-jam-qualification-round.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-1770826058357198319</guid><pubDate>Tue, 04 May 2010 19:08:00 +0000</pubDate><atom:updated>2010-05-04T23:49:20.990+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">fp</category><category domain="http://www.blogger.com/atom/ns#">fsharp</category><title>F# и циклические зависимости.</title><description>&lt;p&gt;Предметом разговора сегодня будет язык программирования F#, который вызвал у меня неслабую зависимость. Я не буду пока рассказывать чем именно, всему свое время. Вместо этого, я хочу обсудить некоторые “недостатки”.&lt;/p&gt;  &lt;p&gt;Главный “недостаток” этого языка программирования, если конечно судить по записям в блогах и сообщениям на форумах – довольно странный для .NET разработчиков механизм компиляции. В C# или VB.NET, порядок компиляции не имеет значения, программист вообще не имеет возможности на него влиять. Мало того, эти языки позволяют с легкостью делать подобное:&lt;/p&gt;  &lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Foo
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;{  
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Bar bar;  
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  ...
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Bar
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;{  
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Foo foo;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  ...
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;То есть, определять классы, которые зависят друг от друга (являются взаимно рекурсивными).&amp;#160; Классы Foo и Bar могут быть в разных файлах, это не имеет значения, компилятор C# во всем прекрасно разберется.&lt;/p&gt;

&lt;p&gt;В случае F#, все не так просто. Во первых, файлы проекта компилируются в строго определенном порядке. И от этого порядка зависит – будет ли проект скомпилирован, или нет. Во вторых, этот порядок определяется программистом. В каком порядке следуют файлы в проекте, в том они и будут компилироваться, в этом порядке и будет работать вывод типов. Если класс Bar зависит от класса Foo, то файл, в котором определен класс Foo должен компилироваться раньше чем файл, в котором определен класс Bar. Предыдущий пример, на F# будет выглядеть так:&lt;/p&gt;

&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;type&lt;/span&gt; Foo =
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    val bar : Bar
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    ...
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;and&lt;/span&gt; Bar =
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    val foo : Foo
&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    ...&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;обратите внимание на ключевое слово and – с его помощью в F# определяются взаимно рекурсивные типы. При этом, оба класса должны находится в одном файле.&lt;/p&gt;

&lt;p&gt;Естественно, это вызывает бурю гневных постов в блогах и на форумах, так-как очень далеко от подхода, используемого в C# и VB.NET.&lt;/p&gt;

&lt;p&gt;Так вот, на самом деле – это очень круто! Круто, потому-что нам пришлось явным образом указать – какие классы являются взаимно рекурсивными. Это означает, что внести в код циклическую зависимость можно только специально.&lt;/p&gt;

&lt;p&gt;Явный порядок компиляции – одна из моих любимых особенностей F#, так как она заставляет программиста заранее продумать архитектуру проекта. Допустим у нас есть большой проект, мы условно разделили его на два слоя – представление и бизнес логику. Классы из presentation слоя – используют классы из business layer-a, а тот в свою очередь – никак не зависит от представления. Если все это добро находится в одной сборке, то нам ничто не мешает использовать код из presentation слоя в бизнес логике. Это будет ошибкой проектирования, тем не менее, многие языки программирования позволяют с легкостью это сделать. С F# этот номер не пройдет, так как файлы слоя представления будут компилироваться позже файлов, содержащих бизнес логику.&lt;/p&gt;

&lt;p&gt;Другое преимущество этого подхода состоит в том, что алгоритм вывода типов становится намного проще, а следовательно работает очень быстро. В частности, благодаря этому, подсказки и сообщения об ошибках в IDE появляются практически мгновенно, что не может не радовать :)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-1770826058357198319?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/KwrKhK3BfwM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/KwrKhK3BfwM/f.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>5</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/05/f.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-7878711936124033315</guid><pubDate>Sat, 20 Mar 2010 10:23:00 +0000</pubDate><atom:updated>2010-03-20T13:26:00.160+03:00</atom:updated><title>Complexity and order</title><description>Современные программы бывают весьма непростыми, поэтому языки программирования содержат средства для борьбы со сложностью. Одним из основных источников сложности, являются зависимости между разными частями приложения. Подобного рода зависимости усложняют внесение изменений в код. Именно этим объясняется популярность ООП - средства борьбы со сложностью подобного рода.

Однако зависимости между разными частями программы - не единственный источник сложности. Помимо этого, очередность выполнения тех или иных действий, может зависеть от каких либо факторов. Например, операция чтения из файла должна выполняться строго после его открытия и до закрытия. Это вносит сложность, так-как вызов метода записи в файл, зависит от того, были ли вызваны другие методы. Все это становится особенно очевидным, при написании многопоточных и асинхронных приложений.

Функциональное программирование, по моему скромному мнению, как раз и является отличным средством для борьбы со сложностью подобного рода. Ведь чаще всего нас не интересует то, в каком порядке выполняются различные действия, нам нужен частичный порядок, а не всеобщий. ФП позволяет решать задачу в декларативном стиле, не определяя явно порядок вызова функций, если это не нужно.

Поэтому для меня очевидно, что будущее именно за теми языками программирования, которые позволят применить одновременно как объектно ориентированный, так и функциональный подход к решению сложных задач.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-7878711936124033315?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/aQSPcV5mJHY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/aQSPcV5mJHY/ordering.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>19</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/03/ordering.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-4792001465845066178</guid><pubDate>Sun, 28 Feb 2010 20:52:00 +0000</pubDate><atom:updated>2010-03-01T01:04:15.769+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">thoughts</category><category domain="http://www.blogger.com/atom/ns#">erlang</category><category domain="http://www.blogger.com/atom/ns#">OOP</category><title>Принципы ООП</title><description>Мне кажется, многие люди неправильно понимают что такое ООП. Если вы попросите любого программиста дать определение ООП, то чаще всего получите один и тот же ответ - ООП, это инкапсуляция, наследование и полиморфизм. На самом деле ООП, это парадигма программирования, согласно которой программа состоит из объектов, обменивающихся сообщениями. Объекты могут обладать состоянием, единственный способ изменить состояние объекта - послать ему сообщение, в ответ на которое, объект может изменить собственное состояние. &lt;span class="Apple-style-span" style="color: rgb(204, 204, 204); "&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;Я знаю, что вы это и так знаете, я про других программистов :)&lt;/span&gt;&lt;/span&gt;&lt;div&gt;Многие вещи, которые мы привыкли причислять к ООП, такие как классы и наследование, это лишь средства моделирования предметной области средствами языка программирования, не более. Теперь по порядку. &lt;/div&gt;&lt;div&gt;
&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;i&gt;Инкапсуляция&lt;/i&gt;.&lt;/span&gt;&lt;div&gt;В программе, состоящей из объектов обменивающихся сообщениями, этот принцип выполняется автоматически. Единственное, что может один объект сделать с другим - послать ему сообщение. Другой объект, отреагировав на это сообщение, может изменить свое состояние. Непосредственно изменять состояние друг друга, в нашей гипотетической true OOP системе, объекты не могут. Следовательно, инкапсуляция, лишь средство, с помощью которого принципы ООП &lt;b&gt;реализуются&lt;/b&gt; в том или ином языке программирования.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;i&gt;Наследование&lt;/i&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Всего лишь позволяет моделировать отношения между сущностями, не между самими объектами. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;i&gt;Полиморфизм.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Обычно его понимают как subtype полиморфизм - использование объекта производного класса, вместо объекта базового класса. Для нашей true OOP системы это не актуально, так как любому объекту, можно послать любое сообщение. Это актуально для тех языков программирования, в которых передача сообщения объекту реализована как вызов виртуального метода этого объекта. &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;В качестве примера true OOP системы программирования, можно привести совсем не ООП&lt;span class="Apple-style-span"  style="color:#C0C0C0;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;(по крайней мере в головах mainstream программистов)&lt;/span&gt;&lt;/span&gt; язык программирования - Erlang. Его процессы - классические объекты, конечно у процесса нет класса, свойств, методов, процессы не наследуются, и так далее. Но, erlang программа - это множество обменивающихся сообщениями процессов/объектов. Получив сообщение, процесс может изменить свое состояние - сделать что-нибудь. Поэтому, erlang - не менее объектно ориентированный, чем Java или Python :)&lt;/div&gt;&lt;div&gt;P.S.&lt;/div&gt;&lt;div&gt;Этим постом я не пытаюсь сказать, что использовать mainstream языки программирования - плохо и что всем нужно срочно переходить на Erlang. Просто мысли вслух :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-4792001465845066178?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/XOKn8mdS-rA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/XOKn8mdS-rA/blog-post.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>14</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/02/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-6197062846705644934</guid><pubDate>Thu, 07 Jan 2010 09:40:00 +0000</pubDate><atom:updated>2010-01-07T12:40:08.717+03:00</atom:updated><title>Dynamic Languages Strike Back</title><description>&lt;blockquote&gt;   &lt;p&gt;I went to the University of Washington and [then] I got hired by this company called Geoworks, doing assembly-language programming, and I did it for &lt;em&gt;five years&lt;/em&gt;. To us, the Geoworkers, we wrote a whole operating system, the libraries, drivers, apps, you know: a desktop operating system in assembly. 8086 assembly! It wasn't even good assembly! We had four registers! [Plus the] si [register] if you counted, you know, if you counted 386, right? It was&lt;em&gt;horrible&lt;/em&gt;.      &lt;br /&gt;I mean, actually we kind of liked it. It was Object-Oriented Assembly. It's amazing what you can talk yourself into liking, which is the real irony of all this. And to us, C++ was the ultimate in Roman decadence. I mean, it was equivalent to going and vomiting so you could eat more. They had IF! We had jump CX zero! Right? They had &amp;quot;Objects&amp;quot;. Well we did too, but I mean they had syntax for it, right? I mean it was all just such weeniness. And we knew that we could outperform any compiler out there because at the time, we could!      &lt;br /&gt;So what happened? Well, they went bankrupt. Why? Now I'm probably disagreeing – I know for a fact that I'm disagreeing with every Geoworker out there. I'm the only one that holds this belief. But it's because we wrote fifteen million lines of 8086 assembly language. We had really good tools, world class tools: trust me, you need 'em. But at some point, man...      &lt;br /&gt;The problem is, picture an ant walking across your garage floor, trying to make a straight line of it. It ain't gonna make a straight line. And you know this because you have &lt;em&gt;perspective&lt;/em&gt;. You can see the ant walking around, going hee hee hee, look at him locally optimize for that rock, and now he's going off this way, right?      &lt;br /&gt;This is what we were, when we were writing this giant assembly-language system. Because what happened was, Microsoft eventually released a platform for mobile devices that was much faster than ours. OK? And I started going in with my debugger, going, what? What is up with this? This rendering is just really slow, it's like sluggish, you know. And I went in and found out that some title bar was getting rendered 140 times every time you refreshed the screen. It wasn't just the title bar. Everything was getting called multiple times.      &lt;br /&gt;Because we couldn't see how the system worked anymore!      &lt;br /&gt;&lt;strong&gt;Small systems are not only &lt;em&gt;easier&lt;/em&gt; to optimize, they're &lt;em&gt;possible&lt;/em&gt; to optimize. And I mean globally optimize.&lt;/strong&gt;      &lt;br /&gt;So when we talk about performance, it's all crap. &lt;strong&gt;The most important thing is that you have a small system.&lt;/strong&gt; And then the performance will just fall out of it naturally.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Отсюда: &lt;a href="http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html"&gt;Stevey's blog rants - Dynamic Languages Strike Back&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-6197062846705644934?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/Y_yn7MCj7L4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/Y_yn7MCj7L4/dynamic-languages-strike-back.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>4</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2010/01/dynamic-languages-strike-back.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-8217659434709039752</guid><pubDate>Fri, 20 Nov 2009 07:49:00 +0000</pubDate><atom:updated>2009-11-20T11:53:19.919+03:00</atom:updated><title>Overengineering</title><description>Здравствуй дорогой дневник. 
Дело в том, что в фирме, в которой я работаю, принят общий стандарт для параметров командной строки. Поэтому, у каждого разработчика есть своя маленькая библиотека для превращения argc и argv в осмысленный набор данных. Велосипедостроение - наше все, поэтому я решил не отставать от остальных и сделать свою библиотеку, с преферансом и блудницами :)
Но просто взять и написать - не спортивно, поэтому я решил использовать Boost.Spirit. Сказано - сделано, есть видимость того, что все работает, но тут возникают проблемы... 
Сначала на тестовых серверах, мои приложения отказываются понимать параметры, содержащие символы кириллицы, в процессе исправления этого бага, оказалось, что spirit-у нельзя подсунуть произвольную локаль. 
Затем, выясняется, что одно мое приложение должно запускаться неким сторонним приложением, в которое намертво зашита командная строка для запуска, причем она самую малость не соответствует нашему внутреннему стандарту и изменить это стороннее приложение нет никакой возможности. Потом, оказалось, что библиотека должна поддерживать не только именованные, но и позиционные параметры, что-то вроде этого: &lt;i&gt;"C:\&gt; program_name.exe positional arguments /Named:parameter"&lt;/i&gt;, и даже логические параметры: &lt;i&gt;"C:\&gt; program_name.exe /FlagName"&lt;/i&gt;.
В итоге, я посмотрел на плод трудов тяжких и понял, что разобраться в этом через месяц будет очень сложно, после чего взял и переписал все заново :)
У меня ушло 20 минут, на то, что-бы написать самый скучный и неинтересный код в моей жизни, если в двух словах, то там есть один большой switch, в каждом case-e которого есть еще один switch :D
И вот этот "быдло-код" ушел в production, прекрасно работает, с ним не было никаких проблем. Неисповедимы пути твои, Господи :D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-8217659434709039752?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/i9JaAGjwDQU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/i9JaAGjwDQU/overengineering.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>7</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/11/overengineering.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-8549819777370876618</guid><pubDate>Sat, 31 Oct 2009 22:24:00 +0000</pubDate><atom:updated>2009-11-01T01:24:41.271+03:00</atom:updated><title>GC or not GC</title><description>&lt;p&gt;that is the question :)&lt;/p&gt;  &lt;p&gt;Мне часто приходилось встречаться с таким мнением, мол в С++ нет сборки мусора, но она и не нужна, так-как есть умные указатели, с помощью которых можно так-же легко управлять памятью используя подсчет ссылок. Так вот, я думаю, что все это ерунда и попробую сейчас объяснить почему, в качестве примера умного указателя считающего ссылки, буду использовать boost::shared_ptr, под сборщиком мусора, я собираюсь понимать сборщик мусора CLR. :)&lt;/p&gt;  &lt;p&gt;В том случае, если временем жизни объекта управляет сборщик мусора, указатели на объект, это просто указатели. В случае, если мы&lt;font color="#c0c0c0"&gt;(а точнее приложение, которое мы пишем:)&lt;/font&gt; используем подсчет ссылок, то указатель на объект, это два указателя, указатель на сам объект, плюс указатель на переменную, содержащую количество ссылок на этот объект&lt;font color="#c0c0c0"&gt;(не правда ли это прекрасно:)&lt;/font&gt;.&lt;/p&gt;  &lt;p&gt;Операции над указателями: в случае GC, мы просто копируем их, в случае not GC, копирование указателя приводит к изменению счетчика ссылок объекта. Копирование, передача в качестве параметра в функцию, удаление умного указателя, приводят к генерации барьера и изменению счетчика ссылок. К тому-же, сам указатель и его счетчик ссылок, могут находится далеко друг от друга в памяти, а это означает плохую локальность.&lt;/p&gt;  &lt;p&gt;Память, в управляемой сборщиком мусора куче, выделяется быстро, по сути, выделение памяти, это смещение указателя, отделяющего свободную память от занятой, на размер объекта, плюс, некоторые сервисные операции, о которых я ничего не знаю :D. Время, затрачиваемое на выделение участка памяти в неуправляемой куче, зависит от размера этого участка, а так-же от фрагментации памяти, и оно достаточно велико.&lt;/p&gt;  &lt;p&gt;Освобождение памяти: GC делает это достаточно долго, он должен найти недостижимые участки памяти, освободить их а затем дефрагментировать кучу. Но этот процесс достаточно хорошо оптимизирован, современные GC собирают мусор не везде, а только там, где он мог появиться. &lt;/p&gt;  &lt;p&gt;Итак, подведу итог. Если использовать в качестве критерия сложность, то получается следующее: сам по себе, алгоритм подсчета ссылок очень прост, алгоритм работы современного сборщика мусора значительно сложнее. Но с точки зрения разработчика все наоборот. Сложности, связанные со сборкой мусора, берет на себя рантайм, а с подсчетом ссылок должен управляться сам программист. Он должен следить за тем, что-бы не возникали циклические ссылки, что-бы у одного объекта всегда был только один счетчик ссылок и так далее. В случае использования GC, нужно просто стараться не создавать для него лишнюю работу. Ну и самое главное – архитектура становится проще.&lt;/p&gt;  &lt;p&gt;В плане производительности, делайте выводы сами, лично мне они кажутся достаточно очевидными. С днем всех святых! :)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-8549819777370876618?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/1gd_9AIB41M" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/1gd_9AIB41M/gc-or-not-gc.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>14</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/11/gc-or-not-gc.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-3917697086428452293</guid><pubDate>Wed, 09 Sep 2009 08:27:00 +0000</pubDate><atom:updated>2009-09-09T14:07:16.187+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">codejam</category><title>Code Jam</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bitbucket.org/Lazin/alang/downloads/tree.PNG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 297px; height: 189px;" src="http://bitbucket.org/Lazin/alang/downloads/tree.PNG" border="0" alt="" /&gt;&lt;/a&gt;Недавно прошел первый квалификационный раунд конкурса Google Code Jam. Я в нем не участвовал, но, ради развлечения, решил одну из задач - &lt;a href="http://code.google.com/codejam/contest/dashboard?c=90101#"&gt;alien language&lt;/a&gt;.
Суть задачи такова: у нас есть две последовательности строк. Первая, состоит из N разных строк одинаковой длины(abc, cda, ...). Вторая - из М строк вида: (abc)cd, где в скобках перечислены все возможные значения, которые являются шаблонами для поиска в первой последовательности. К примеру, шаблону (abc)cd, будут соответствовать три строки - acd, bcd и ccd. Цель - посчитать количество строк из первой последовательности, которые соответствуют каждому из шаблонов из второй последовательности.&lt;div&gt;Решение в лоб - создать хэш таблицу из элементов первой последовательности. Затем для каждого из шаблонов, получить список всех возможных строк, которые соответствуют данному шаблону. После этого нужно выполнить поиск каждой из созданных строк в хэш таблице. Нам нужно определить количество удачных операций поиска для каждого из шаблонов.&lt;/div&gt;&lt;div&gt;Не трудно понять, что уже при достаточно небольшой длине строки, мы получим &lt;a href="http://en.wikipedia.org/wiki/Combinatorial_explosion"&gt;комбинаторный взрыв&lt;/a&gt;. Количество вариантов, которые нужно проверить будет огромным.
Самое простое решение задачи - преобразовать каждый из шаблонов в регулярное выражение, а затем посчитать количество совпадений. Но, это совсем не интересно :)

Вместо этого, я построил свой алгоритм, который не перебирает все возможные строки, подходящие к шаблону. Он ищет(и считает) совпадения в дереве, каждый узел которого может содержать до 26-ти потомков(на рисунке). Каждый из потомков соответствует одному из символов английского алфавита. Первому уровню дерева(узел показан зеленым цветом) соответствуют первые символы всех строк входной последовательности. Второму уровню(показан синим) - вторые символы, и так далее... Соответственно, что-бы проверить, есть-ли строка "abc" среди входных данных, нужно проверить, есть-ли в корневом узле дерева, поддерево, соответствующее символу 'a', затем, рекурсивно, найти в этом поддереве потомка, соответствующего символу 'b' и тд. Затем, если мы прошли ветвь дерева, соответствующую строке "abc", мы легко можем перейти к ветви, соответствующей подстроке "abd" либо "abb". В общем, алгоритм обхода дерева достаточно очевиден.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Работает это правильно и достаточно шустро. Я не измерял время работы, но по ощущениям, большой набор данных, был обработан не больше чем за две секунды :)&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;a href="http://bitbucket.org/Lazin/alang/src/tip/ALang.cpp"&gt;исходник&lt;/a&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-3917697086428452293?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/M7aY3x0UtGI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/M7aY3x0UtGI/code-jam-google-code-jam.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>11</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/09/code-jam-google-code-jam.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-3960159586946249001</guid><pubDate>Sun, 16 Aug 2009 16:14:00 +0000</pubDate><atom:updated>2009-08-16T20:14:46.140+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">C++</category><title>C++Next</title><description>&lt;p&gt;Пару недель назад Дэвид Абрамс и Дуг Грегор начали вести блог - &lt;a href="http://cpp-next.com/"&gt;C++Next&lt;/a&gt;. На данный момент там только две статьи, надеюсь, что это не надолго :)&lt;/p&gt;  &lt;p&gt;В общем, очень рекомендую, будет интересно!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-3960159586946249001?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/0a8urKzf_pg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/0a8urKzf_pg/cnext.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/08/cnext.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-4350814033302763154</guid><pubDate>Sat, 02 May 2009 12:46:00 +0000</pubDate><atom:updated>2009-05-02T19:23:57.451+04:00</atom:updated><title>Boost.Preprocessor</title><description>Препроцессор - штука достаточно неодназначная, что-бы это понять, достаточно поднять дискуссию на эту тему на каком-нибудь формуе, и опасная, так-как он вообще не в курсе синтаксиса языка программирования С++, ничего не знает о пространствах имен, шаблонах и тд. Лучше всего ограничить его применение условной компиляцией а так-же не забывать использовать #undef. Но, если не следовать этой рекомендации, то с его помощью можно делать очень интересные вещи :)
Это можно продемонстрировать на примере списков типов, которые описаны в книге Александресску - "Современное проектирование на С++".
Вот реализация такого списка
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;struct&lt;/span&gt; empty_t &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;

&lt;span style='color:#800000; font-weight:bold; '&gt;template&lt;/span&gt;&lt;span style='color:#800080; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; Head&lt;span style='color:#808030; '&gt;,&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; Tail&lt;span style='color:#800080; '&gt;&gt;&lt;/span&gt;
&lt;span style='color:#800000; font-weight:bold; '&gt;struct&lt;/span&gt; cons
&lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;typedef&lt;/span&gt; Head head&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;typedef&lt;/span&gt; Tail tail&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;/pre&gt;а использовать его можно так:&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;typedef&lt;/span&gt; cons&lt;span style='color:#800080; '&gt;&amp;lt;&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;int&lt;/span&gt;&lt;span style='color:#808030; '&gt;,&lt;/span&gt; cons&lt;span style='color:#800080; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;long&lt;/span&gt;&lt;span style='color:#808030; '&gt;,&lt;/span&gt; cons&lt;span style='color:#800080; '&gt;&amp;lt;&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;double&lt;/span&gt;&lt;span style='color:#808030; '&gt;,&lt;/span&gt; empty_t &lt;span style='color:#800080; '&gt;&gt;&lt;/span&gt; &lt;span style='color:#800080; '&gt;&gt;&lt;/span&gt; &lt;span style='color:#800080; '&gt;&gt;&lt;/span&gt; tl_first&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;/pre&gt;Но это совсем не удобно, что-бы это исправить, нужен более простой способ объявления списков типов.&lt;span class="fullpost"&gt; Самый простой способ это сделать - макросы a-la Александресску:&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TYPE_LIST_1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;t&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; cons&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; empty_t &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TYPE_LIST_2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;t1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; cons&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TYPE_LIST_1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;t2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TYPE_LIST_3&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;t1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t3&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; cons&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t1&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TYPE_LIST_2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;t2&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; t3&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; TYPE_LIST_3(&lt;span style='color:#7f0055; font-weight:bold; '&gt;int&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;long&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;double&lt;/span&gt;) tl_second;
&lt;/pre&gt;Это просто и понятно, но не очень удобно, хотелось-бы избавиться от размера списка в имени макроса. 
То-же самое можно реализовать и без макросов, используя шаблоны:&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;template&lt;/span&gt;&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T1, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T2 = empty_t, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T3 = empty_t, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T4 = empty_t&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;struct&lt;/span&gt; make_typelist;


&lt;span style='color:#7f0055; font-weight:bold; '&gt;template&lt;/span&gt;&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T1&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;struct&lt;/span&gt; make_typelist&amp;lt;T1, empty_t, empty_t, empty_t&gt;
{
    &lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; cons&amp;lt;T1, empty_t&gt; type;
};

&lt;span style='color:#7f0055; font-weight:bold; '&gt;template&lt;/span&gt;&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T1, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T2&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;struct&lt;/span&gt; make_typelist&amp;lt;T1, T2, empty_t, empty_t&gt;
{
    &lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; cons&amp;lt;T1, cons&amp;lt;T2, empty_t&gt; &gt; type;
};

&lt;span style='color:#7f0055; font-weight:bold; '&gt;template&lt;/span&gt;&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T1, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T2, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T3&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;struct&lt;/span&gt; make_typelist&amp;lt;T1, T2, T3, empty_t&gt;
{
    &lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; cons&amp;lt;T1, cons&amp;lt;T2, cons&amp;lt;T3, empty_t&gt; &gt; &gt; type;
};
&lt;/pre&gt;теперь достаточно написать:&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; make_typelist&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;int&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;long&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;double&lt;/span&gt;&gt;::type tl_third;
&lt;/pre&gt;и у нас есть список типов. В этом коде мы сталкиваемся с одним из недостатков языка С++ - отсутствием шаблонов с переменным числом параметров, поэтому приходится описывать все необходимые специализации. Страшно представить, что будет, если нам потребуется создать список хотя-бы из десяти элементов. И вот здесь нам может помочь библиотека boost.preprocessor. С ее помощью можно написать вот такой &lt;s&gt;нечитаемый&lt;/s&gt; код:&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;include &lt;/span&gt;&lt;span style='color:#2a00ff; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#3f3fbf; '&gt;boost/preprocessor/repetition.hpp&lt;/span&gt;&lt;span style='color:#2a00ff; '&gt;&gt;&lt;/span&gt;
&lt;span style='color:#3f7f59; '&gt;//boost preprocessor&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; MAX_TYPELIST_SIZE 4&lt;/span&gt;

&lt;span style='color:#7f0055; font-weight:bold; '&gt;template&lt;/span&gt;&amp;lt; BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(MAX_TYPELIST_SIZE, &lt;span style='color:#7f0055; font-weight:bold; '&gt;class&lt;/span&gt; T, empty_t)&gt;
&lt;span style='color:#7f0055; font-weight:bold; '&gt;struct&lt;/span&gt; make_typelist;

&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TUPLE_PRINT&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;n&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; data&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; data&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;define&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; GEN_MAKETYPELIST&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;n&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; unused&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                  \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;template&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; BOOST_PP_ENUM_PARAMS&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; class T&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                            \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;struct make_typelist&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                                   \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;BOOST_PP_ENUM_PARAMS&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;T&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                         \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;BOOST_PP_COMMA_IF&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                              \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;BOOST_PP_ENUM&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                                    \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;BOOST_PP_SUB&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;MAX_TYPELIST_SIZE&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TUPLE_PRINT&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; empty_t&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;    \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;{&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                                                                       \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;typedef BOOST_PP_ENUM_PARAMS&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; cons&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;T&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; empty_t                    \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;&amp;#xa0;BOOST_PP_REPEAT&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;(&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;i&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TUPLE_PRINT&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;,&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;&gt;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; &lt;/span&gt;&lt;span style='color:#7f0055; '&gt;)&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; type&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;;&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;                   \&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;}&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;;&lt;/span&gt;

BOOST_PP_REPEAT_FROM_TO(1, MAX_TYPELIST_SIZE, GEN_MAKETYPELIST, ~)

&lt;span style='color:#7f0055; font-weight:bold; '&gt;typedef&lt;/span&gt; make_typelist&amp;lt;&lt;span style='color:#7f0055; font-weight:bold; '&gt;int&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;long&lt;/span&gt;, &lt;span style='color:#7f0055; font-weight:bold; '&gt;double&lt;/span&gt;&gt;::type tl_third;

&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;undef&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; TUPLE_PRINT&lt;/span&gt;
&lt;span style='color:#7f0055; '&gt;#&lt;/span&gt;&lt;span style='color:#7f0055; '&gt;undef&lt;/span&gt;&lt;span style='color:#7f0055; '&gt; GEN_MAKETYPELIST&lt;/span&gt;
&lt;/pre&gt;В этом примере, препроцессор создаст точно такой-же код как и в предидущем примере. Но теперь, в случае если нам потребуется увеличить максимальный размер списка типов для make_typelist, достаточно изменить MAX_TYPELIST_SIZE. Многие библиотеки boost используют подобную технику для эмуляции шаблонов с переменным количеством параметров, например boost.tuple.
В данном конкретном случае, макрос GEN_MAKETYPELIST создает одну из специализаций шаблонного класса make_typelist, в качестве параметров он получает максимальный размер списка типов(n), и количество параметров шаблона(i). Этот макрос используется в BOOST_PP_REPEAT_FROM_TO, для генерации всех необходимых специализаций шаблона.
Сама библиотека boost.preprocessor - достаточно простая. Начать ее использовать очень легко, главное знать, для чего она может быть полезна. 
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-4350814033302763154?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/LDm_t5eIZEI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/LDm_t5eIZEI/boostpreprocessor.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>4</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/05/boostpreprocessor.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-5435347051741615366</guid><pubDate>Tue, 31 Mar 2009 09:05:00 +0000</pubDate><atom:updated>2009-03-31T13:08:50.611+04:00</atom:updated><title>PEP-374</title><description>Сегодня GvR объявил о том, что python переходит на mercurial. По ссылке неплохой обзор трех DVCS и SVN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-5435347051741615366?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/EP4bd_m6FeY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/EP4bd_m6FeY/pep-374.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>0</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/03/pep-374.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7754674872362895099.post-5567410450057757722</guid><pubDate>Tue, 24 Mar 2009 13:03:00 +0000</pubDate><atom:updated>2009-03-24T16:38:55.443+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">unit-test</category><category domain="http://www.blogger.com/atom/ns#">boost</category><category domain="http://www.blogger.com/atom/ns#">asio</category><title>Unit тестирование и boost::asio</title><description>Как известно, одно из главных требований к модульным тестам, это повторяемость. Очень сложно искать ошибку, которая воспроизводится через раз. А с кодом, использующим асинхронный ввод вывод, все обычно так и обстоит, как как обработчики различных событий, обычно, выполняются в неопределенном порядке, к тому-же из разных потоков. Но, если вы используете boost::asio, то все не так плохо. Эта библиотека спроектирована так, что-бы её можно было легко испоьзовать в модульных тестах. 
Представим, что у нас есть два класса, клиент и сервер, оба используют boost::asio для асинхронного IO. Для того, что-бы написать для них тест, нам нужно создать два io_service-a, так-как в они будут работать независимо. Далее, мы можем вызывать различные функции, которые начинают асинхронные операции, например запись данных в сокет, или ожидание подключения клиента. Но, вместо того, что-бы вызывать метод io_service::run, мы можем вызвать метод io_service::run_one, который выполняет обработчик только одного события. Благодаря этому, асинхронный код можно превратить в линейный и протестировать таким образом логику наших классов.

&lt;pre style='color:#000000;background:#ffffff;'&gt;TEST(MyTest, test_async_connect)
{
    boost::io_service client_io, server_io;

    my_client client(client_io);
    my_server server(server_io);
    
    EXPECT_FALSE(client.connected());&lt;span style='color:#3f7f59; '&gt;//connected возвращает false, если клиент не подключен к серверу&lt;/span&gt;
    EXPECT_EQ(server.clients_count(), 0);&lt;span style='color:#3f7f59; '&gt;//к серверу не подключен ни один клиент&lt;/span&gt;
    server.start_accept();&lt;span style='color:#3f7f59; '&gt;//начинаем принимать подключения&lt;/span&gt;
    client.async_connect(&lt;span style='color:#2a00ff; '&gt;"&lt;/span&gt;&lt;span style='color:#2a00ff; '&gt;localhost&lt;/span&gt;&lt;span style='color:#2a00ff; '&gt;"&lt;/span&gt;, my_port);&lt;span style='color:#3f7f59; '&gt;//метод async_connect, &lt;/span&gt;
    &lt;span style='color:#3f7f59; '&gt;//начинает асинхронную операцию подключения к серверу,&lt;/span&gt;
    &lt;span style='color:#3f7f59; '&gt;//в коде my_client, это может быть реализовано примерно так:&lt;/span&gt;
    &lt;span style='color:#3f7f59; '&gt;//  boost::asio::async_connect(thsi-&gt;socket_, &amp;amp;my_client::on_connect);&lt;/span&gt;
    &lt;span style='color:#3f7f59; '&gt;//естественно, метод on_connect, должен изменить состояние клиента&lt;/span&gt;
    server_io.run_one();&lt;span style='color:#3f7f59; '&gt;//во время этого вызова, сервер дожен принять подключение,&lt;/span&gt;
    &lt;span style='color:#3f7f59; '&gt;//обработать сообветствующее событие и изменить свое состояние&lt;/span&gt;
    EXPECT_EQ(server.clients_count(), 1);&lt;span style='color:#3f7f59; '&gt;//теперь клиент подключен к серверу&lt;/span&gt;
    EXPECT_FALSE(client.connected());&lt;span style='color:#3f7f59; '&gt;//но сам еще не знает об этом&lt;/span&gt;
    client_io.run_one();&lt;span style='color:#3f7f59; '&gt;//что-бы он об этом узнал, нужно что-бы выполнился обработчик собыитя on_connect&lt;/span&gt;
    EXPECT_TRUE(client.connected());&lt;span style='color:#3f7f59; '&gt;//done&lt;/span&gt;
}
&lt;/pre&gt;
&lt;span class="fullpost"&gt;

&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7754674872362895099-5567410450057757722?l=evgeny-lazin.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/evgeny-lazin/~4/rOb2SdJpaoI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/evgeny-lazin/~3/rOb2SdJpaoI/unit-boostasio.html</link><author>noreply@blogger.com (Евгений Лазин)</author><thr:total>5</thr:total><feedburner:origLink>http://evgeny-lazin.blogspot.com/2009/03/unit-boostasio.html</feedburner:origLink></item></channel></rss>

