<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>bazhenov.me</title><link>https://www.bazhenov.me/</link><description>Recent content on bazhenov.me</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 24 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.bazhenov.me/rss.xml" rel="self" type="application/rss+xml"/><item><title>The Two Thread IDs of macOS: Measuring P/E Core Usage on Apple Silicon</title><link>https://www.bazhenov.me/posts/apple-silicon-measure-pe-usage/</link><pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/apple-silicon-measure-pe-usage/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I needed a straightforward way to check programmatically how much time a process spends on P-cores vs E-cores. There&amp;rsquo;s no high-level API for it, at least not that I know of – and yet this information matters whenever you care about consistent performance on Apple Silicon.&lt;/p&gt;
&lt;p&gt;I ran into this while working on &lt;a href="https://github.com/bazhenov/tango" class="external-link" target="_blank" rel="noopener"&gt;Tango.rs&lt;/a&gt;, a benchmarking framework. When comparing two algorithms, if one happens to run mostly on P-cores while the other gets pushed to E-cores, you&amp;rsquo;re not comparing algorithms anymore – you&amp;rsquo;re comparing hardware. I needed to check the proportion of time each process spends on P and E cores.&lt;/p&gt;</description></item><item><title>Activity Monitor Anatomy</title><link>https://www.bazhenov.me/posts/activity-monitor-anatomy/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/activity-monitor-anatomy/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Imagine you opened Activity Monitor to check how much memory your application consumes.&lt;/p&gt;


 
 
 &lt;a href="https://www.bazhenov.me/posts/activity-monitor-anatomy/activity-monitor.png"&gt;
 &lt;img src="https://www.bazhenov.me/posts/activity-monitor-anatomy/activity-monitor_hu_b71063a0856df17e.png" alt=""&gt;
 &lt;/a&gt;
 

&lt;p&gt;But wait, which number should you actually look at? Suppose there&amp;rsquo;s &amp;ldquo;Memory&amp;rdquo; showing 800 MB, and &amp;ldquo;Real Memory&amp;rdquo; showing 1 GB. What&amp;rsquo;s the difference?&lt;/p&gt;
&lt;div class="notice note"&gt;
 &lt;div class="notice-title"&gt;
 &lt;i class="fa-solid fa-sticky-note" aria-hidden="true"&gt;&lt;/i&gt;Note
 &lt;/div&gt;
 &lt;div class="notice-content"&gt;Activity Monitor doesn&amp;rsquo;t display those two readings by default. To show them, you need to right-click on a table header and select them.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This exact scenario happened to me more times than I&amp;rsquo;d like to admit. As someone who keeps Activity Monitor perpetually open, I found myself constantly puzzled by these two memory metrics. Coming from a Linux background where RSS (Resident Set Size) tells a straightforward story, macOS&amp;rsquo;s dual memory reporting felt like reading tea leaves.&lt;/p&gt;</description></item><item><title>Performance Roulette: The Luck of Code Alignment</title><link>https://www.bazhenov.me/posts/2024-02-performance-roulette/</link><pubDate>Wed, 14 Feb 2024 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/2024-02-performance-roulette/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Good weather is specific weather. Conclusion: there is no such thing as good weather.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Pilot&amp;rsquo;s proverb&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; The very same machine code, placed at different addresses, can exhibit drastically different performance.&lt;/p&gt;
&lt;p&gt;As software developers, we often assume that the performance of a specific piece of code is determined solely by the code itself and the hardware it runs on. This assumption gives us a sense of control when optimizing code for better performance. While this assumption holds true in most cases, this article aims to explore phenomena that challenge this notion of control. Additionally, I will provide a &lt;a href="https://github.com/bazhenov/same-code-different-performance" class="external-link" target="_blank" rel="noopener"&gt;sandbox&lt;/a&gt; to demonstrate this phenomenon using the Rust programming language.&lt;/p&gt;</description></item><item><title>Paired benchmarking. How to measure performance</title><link>https://www.bazhenov.me/posts/paired-benchmarking/</link><pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/paired-benchmarking/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;In this article, I discuss the &lt;a href="#challenges" &gt;challenges&lt;/a&gt; associated with testing algorithm performance, focusing primarily on microbenchmarks rather than overall application performance, although some principles apply to both. I provide a &lt;a href="#addressing" &gt;brief overview of efforts to address&lt;/a&gt; these challenges and highlight some limitations we&amp;rsquo;re encountering.&lt;/p&gt;
&lt;p&gt;Subsequently, I introduce an alternative method of performance testing called &lt;a href="#paired" &gt;paired benchmarking&lt;/a&gt;, which effectively tackles some of these challenges. While paired testing is a &lt;a href="https://en.wikipedia.org/wiki/Paired_difference_test" class="external-link" target="_blank" rel="noopener"&gt;well-known statistical technique&lt;/a&gt;, as far as I am aware, it has not yet been implemented in any benchmarking tools.&lt;/p&gt;</description></item><item><title>Compress-a-Palooza: Unpacking 5 Billion Varints in only 4 Billion CPU Cycles</title><link>https://www.bazhenov.me/posts/rust-stream-vbyte-varint-decoding/</link><pubDate>Sun, 21 May 2023 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/rust-stream-vbyte-varint-decoding/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Varint is a widely recognized technique used for compressing integer streams. Essentially, it suggests that it can be more efficient to encode a number using a variable-length representation instead of a fixed-size binary representation. By removing leading zeros from the binary number, the overall representation size can be reduced. This technique works particularly well for encoding smaller numbers.&lt;/p&gt;
&lt;p&gt;In this article, I provide a brief introduction and rationale for varint encoding. Additionally, I describe the &lt;a href="https://arxiv.org/abs/1709.08990" class="external-link" target="_blank" rel="noopener"&gt;Stream VByte&lt;/a&gt; format, which enables fully vectorized decoding through SSSE3 instructions. I also share my findings from &lt;a href="https://github.com/bazhenov/svbyte" class="external-link" target="_blank" rel="noopener"&gt;implementing this algorithm in Rust&lt;/a&gt;, which includes both encoding and decoding primitives and the ability to read data from both RAM and disk.&lt;/p&gt;</description></item><item><title>Fast(er) binary search in Rust</title><link>https://www.bazhenov.me/posts/faster-binary-search-in-rust/</link><pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/faster-binary-search-in-rust/</guid><description>&lt;h2 id="introducton"&gt;
 Introducton
 &lt;a class="heading-link" href="#introducton"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Binary search is a very fast algorithm. Due to its exponential nature, it can process gigabytes of sorted data quickly. However, two problems make it somewhat challenging for modern CPUs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;predictability of instruction flow;&lt;/li&gt;
&lt;li&gt;predictability of memory access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At each step, binary search splits the dataset into two parts and jumps to one of those parts based on a midpoint value. It&amp;rsquo;s difficult for the CPU to predict which parts of the presumably large array will be accessed in the next iteration. As a result, binary search produces many cache misses, which stalls the CPU pipeline, resulting in poor instruction-per-clock performance.&lt;/p&gt;</description></item><item><title>How fast can you count to 16 in Rust?</title><link>https://www.bazhenov.me/posts/counting-to-16-in-rust/</link><pubDate>Mon, 10 Apr 2023 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/counting-to-16-in-rust/</guid><description>&lt;h2 id="introduction"&gt;
 Introduction
 &lt;a class="heading-link" href="#introduction"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Suppose we need to write a function that computes the next set of numbers in a range and stores them in a slice, as shown below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e0def4;background-color:#191724;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#31748f"&gt;let&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;pl&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;RangePl&lt;/span&gt;::&lt;span style="color:#ebbcba"&gt;new&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;1&lt;/span&gt;&lt;span style="color:#908caa"&gt;..&lt;/span&gt;&lt;span style="color:#f6c177"&gt;12&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#31748f"&gt;let&lt;/span&gt; &lt;span style="color:#31748f"&gt;mut&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;buffer&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#908caa"&gt;[&lt;/span&gt;&lt;span style="color:#f6c177"&gt;0&lt;/span&gt;&lt;span style="color:#31748f"&gt;u64&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt; &lt;span style="color:#f6c177"&gt;4&lt;/span&gt;&lt;span style="color:#908caa"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;pl&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;next_batch&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;0&lt;/span&gt;&lt;span style="color:#908caa"&gt;,&lt;/span&gt; &lt;span style="color:#908caa"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#31748f"&gt;mut&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;buffer&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt; &lt;span style="color:#6e6a86"&gt;// returns 4, buffer[..] = [1, 2, 3, 4]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;pl&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;next_batch&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;0&lt;/span&gt;&lt;span style="color:#908caa"&gt;,&lt;/span&gt; &lt;span style="color:#908caa"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#31748f"&gt;mut&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;buffer&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt; &lt;span style="color:#6e6a86"&gt;// returns 4, buffer[..] = [5, 6, 7, 8]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;pl&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;next_batch&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;10&lt;/span&gt;&lt;span style="color:#908caa"&gt;,&lt;/span&gt; &lt;span style="color:#908caa"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#31748f"&gt;mut&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;buffer&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt; &lt;span style="color:#6e6a86"&gt;// returns 2, buffer[0..2] = [10, 11]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;pl&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;next_batch&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;10&lt;/span&gt;&lt;span style="color:#908caa"&gt;,&lt;/span&gt; &lt;span style="color:#908caa"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#31748f"&gt;mut&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;buffer&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt; &lt;span style="color:#6e6a86"&gt;// returns 0, buffer not updated
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key factors:&lt;/p&gt;</description></item><item><title>Why Clean Code was (and still is) important?</title><link>https://www.bazhenov.me/posts/why-clean-code-was-important/</link><pubDate>Tue, 28 Mar 2023 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/posts/why-clean-code-was-important/</guid><description>&lt;p&gt;In recent years, criticism of the classic object-oriented analysis and design ideas has grown increasingly louder. One example of such criticism is &lt;a href="https://www.computerenhance.com/p/clean-code-horrible-performance" class="external-link" target="_blank" rel="noopener"&gt;Clean Code, Horrible Performance&lt;/a&gt; by Case Muratori.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quote that explains the author&amp;rsquo;s idea:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It simply cannot be the case that we&amp;rsquo;re willing to give up a decade or more of hardware performance just to make programmers’ lives a little bit easier. Our job is to write programs that run well on the hardware that we are given. If these rules cause software to perform this poorly, they simply aren&amp;rsquo;t acceptable.&lt;/p&gt;</description></item><item><title>Java, futex, 2 gc</title><link>https://www.bazhenov.me/blog/2017/10/19/java-futext-2-gc.html</link><pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2017/10/19/java-futext-2-gc.html</guid><description>&lt;p&gt;Недавно на работе произошла следующая ситуация, потребовавшая не совсем тривиальной диагностики. Есть Java-приложение, выполняющее пакетную обработку информации. Обработка выполняется последовательно в несколько стадий. Каждая стадия выполняется в нескольких потоках. Несмотря на высокую требовательность к процессорному времени, приложение не может полностью утилизировать ресурсы сервера. В чем же дело?&lt;/p&gt;
&lt;p&gt;Довольно быстро появилась гипотеза, что дело в GC, который добавляет паузы в работу приложения и не позволяет польностью утилизировать CPU. Гипотеза согласовывалась с тем что сообщали нам &lt;code&gt;jstat&lt;/code&gt; и JFR. Но чтобы понять как лучше оптимизировать приложение, было необходимо оценить степень влияния GC на потоки одной конкретной стадии, а не на все приложение в целом. Именно эта стадия была узким местом. Ни &lt;code&gt;jstat&lt;/code&gt; ни JFR этого не умеют.&lt;/p&gt;</description></item><item><title>Объединение линейных счётчиков</title><link>https://www.bazhenov.me/blog/2016/06/28/linear-counter-merge.html</link><pubDate>Tue, 28 Jun 2016 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2016/06/28/linear-counter-merge.html</guid><description>&lt;p&gt;Линейный счётчик — это очень &lt;a href="https://www.bazhenov.me/blog/2012/12/12/linear-counter.html" &gt;простой алгоритм оценки мощности множества&lt;/a&gt;. Тем не менее, у него есть одна не очевидная и очень полезная особенность. Побитовая сумма (логическое ИЛИ) двух линейных счётчиков позволяет оценить мощность объединения двух множеств.&lt;/p&gt;
&lt;p&gt;Например, у вас есть два множества $A$ и $B$, а также их линейные счётчики $A&amp;rsquo;$, $B&amp;rsquo;$. Тогда:&lt;/p&gt;
&lt;p&gt;$$L_{A&amp;rsquo; | B&amp;rsquo;} \approx |A \cup B|$$&lt;/p&gt;
&lt;p&gt;где $L_x$ – функция оценки линейного счётчика.&lt;/p&gt;
&lt;p&gt;Это свойство крайне полезно для оценки, например, количества уникальных посетителей того или иного ресурса за произвольный промежуток времени.&lt;/p&gt;</description></item><item><title>Как замедлить систему в три раза чтобы пользователь не заметил</title><link>https://www.bazhenov.me/blog/2015/08/11/slow-down.html</link><pubDate>Tue, 11 Aug 2015 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2015/08/11/slow-down.html</guid><description>&lt;p&gt;Иногда по долгу службы приходится проводить деструктивные эксперименты. Делаем мы это лишь для того чтобы сделать нашу систему более стабильной и надёжной.&lt;/p&gt;
&lt;p&gt;Недавно мы провели такой эксперимент, связанный с проверкой алгоритма балансировки внутри поисковой системы. Суть эксперимента заключалась в проверке того, что алгоритм в состоянии распределить запросы между репликам в соответствии с их текущей пропускной способностью. Если какая-то реплика стала медленней обрабатывать запросы, она должна получать пропорционально меньшее количество запросов.&lt;/p&gt;</description></item><item><title>LXC для разработчика</title><link>https://www.bazhenov.me/blog/2015/02/11/lxc-for-developer.html</link><pubDate>Wed, 11 Feb 2015 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2015/02/11/lxc-for-developer.html</guid><description>&lt;p&gt;Работая над более менее сложным проектом, приходится поддерживать окружение необходимое для корректного функционирования системы. Нередко это выливается в ситуацию, когда на машине установлено такое количество пакетов и зависимостей, что возникает масса проблем:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;окружение становится тяжёло воспроизвести на другой машине (например, новому разработчику);&lt;/li&gt;
&lt;li&gt;окружение становится хрупким. Обновляя зависимости для какой-нибудь вспомогательной утилиты, ломается основной проект;&lt;/li&gt;
&lt;li&gt;окружение тяжело поддаётся изменениям. Хочется поэксперементировать с какой-нибудь библиотекой, но из за опасности накосячить с зависимостями, от этой затеи приходится отказаться.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;На Java-платформе эти проблемы менее заметны за счёт развитых инструментов управления зависимостей, а также замкнутости платформы. В экосистеме Java не очень жалут C/C++ библиотеки. Все популярные драйвера и библиотеки написаны непосредственно на Java, поэтому не возникает проблем с управлением системными зависимостями. А для управления библиотеками в Java есть масса зрелых инструментов.&lt;/p&gt;</description></item><item><title>Top 10 фич Java 8 о которых не говорят</title><link>https://www.bazhenov.me/blog/2014/07/20/java-8-top10.html</link><pubDate>Sun, 20 Jul 2014 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2014/07/20/java-8-top10.html</guid><description>&lt;p&gt;О новых фичах Java 8 &lt;a href="https://leanpub.com/whatsnewinjava8/read" class="external-link" target="_blank" rel="noopener"&gt;было&lt;/a&gt; &lt;a href="http://www.takipiblog.com/2014/03/18/5-features-in-java-8-that-will-change-how-you-code/" class="external-link" target="_blank" rel="noopener"&gt;сказано&lt;/a&gt; &lt;a href="http://www.techempower.com/blog/2013/03/26/everything-about-java-8/" class="external-link" target="_blank" rel="noopener"&gt;уже&lt;/a&gt; &lt;a href="http://www.javaworld.com/article/2078836/java-se/love-and-hate-for-java-8.html" class="external-link" target="_blank" rel="noopener"&gt;довольно&lt;/a&gt; &lt;a href="http://ttux.net/post/java-8-new-features-release-performance-code/" class="external-link" target="_blank" rel="noopener"&gt;много&lt;/a&gt;. В основном обсуждают замыкания, Stream&amp;rsquo;ы, новое API для работы со временем, default-методы в интерфейсах, класс Optional и отсутствие Permanent Generation.&lt;/p&gt;
&lt;p&gt;Но помимо жирных фич, в Java 8 сильно изменилась стандартная библиотека по перифирии. В частности, в уже существующие классы было добавлено много методов существенно упрощающих ежедневные задачи. Об этом мы сегодня и поговорим.&lt;/p&gt;
&lt;!--excerpt--&gt;
&lt;p&gt;Итак, Top 10 самых не обсуждаемых фич Java 8. Поехали.&lt;/p&gt;
&lt;h2 id="stringjoin"&gt;
 String.join()
 &lt;a class="heading-link" href="#stringjoin"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Неужто свершилось?! 2014 год на дворе, а в стандартной библиотеке Java появился метод объединяющий набор строк в одну с заданным разделителем.&lt;/p&gt;</description></item><item><title>Классификация методом максимальной энтропии</title><link>https://www.bazhenov.me/blog/2013/04/23/maximum-entropy-classifier.html</link><pubDate>Tue, 23 Apr 2013 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2013/04/23/maximum-entropy-classifier.html</guid><description>&lt;p&gt;&lt;a href="https://www.bazhenov.me/blog/2012/06/11/naive-bayes.html" &gt;Наивный байесовский классификатор&lt;/a&gt;, о котором я уже писал, один из самых простых классификационных алгоритмов. В этой заметке я опишу более сложный алгоритм — &lt;a href="http://en.wikipedia.org/wiki/Principle_of_maximum_entropy" class="external-link" target="_blank" rel="noopener"&gt;метод максимальной энтропии&lt;/a&gt;, который, в ряде случаев, может оказаться существенно более точным. К своему удивлению, я не нашел в рунете более менее полного описания этого алгоритма классификации. Поэтому, считаю полезным поделиться этими знаниями.&lt;/p&gt;
&lt;p&gt;Как и в предыдущем случае, описание разбито на две части: &lt;a href="#theory" &gt;теорию&lt;/a&gt; и &lt;a href="#practice" &gt;практику&lt;/a&gt;. В теоретической части описываются вопросы связанные с математической моделью классификатора. В практической части, содержится описание, как максимально быстро получить работающий классификатор для практических нужд на Java. Исходный код работающего примера &lt;a href="https://github.com/bazhenov/maxent-example" class="external-link" target="_blank" rel="noopener"&gt;доступен на github&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Размер линейного счетчика</title><link>https://www.bazhenov.me/blog/2013/04/14/linear-counter-bitmask-size.html</link><pubDate>Sun, 14 Apr 2013 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2013/04/14/linear-counter-bitmask-size.html</guid><description>&lt;p&gt;Для использования &lt;a href="https://www.bazhenov.me/blog/2012/12/12/linear-counter.html" &gt;линейного счетчика&lt;/a&gt; необходимо заранее знать приблизительное количество уникальных элементов в потоке. На основании этого количества, а также необходимого вам уровня точности, вычисляется длина битовой маски счетчика.&lt;/p&gt;
&lt;p&gt;Допустим, вы хотите создать линейный счетчик для оценки количества элементов в потоке, с максимальным количеством уникальных элементов равным 10 миллионам. Какой длины должна быть битовая маска? Ответ на этот вопрос позволяет найти следующее неравенство:&lt;/p&gt;
&lt;p&gt;$$m &amp;gt; \max\left(5, \frac{1}{(\epsilon t)^2}\right) \left(e^t - t - 1\right)$$&lt;/p&gt;</description></item><item><title>Архитектура поисковых систем</title><link>https://www.bazhenov.me/blog/2013/01/08/search-architecture.html</link><pubDate>Tue, 08 Jan 2013 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2013/01/08/search-architecture.html</guid><description>&lt;p&gt;Так уж получилось, что последние несколько лет я занимаюсь вопросами, связанными с поиском. Один из проектов, завершенных в прошлом году, был связан с модифицированием архитектуры нашей поисковой системы. В итоге мы получили результаты, которыми, как я считаю, имеет смысл поделиться. So, here we go.&lt;/p&gt;
&lt;h2 id="функциональность-поисковой-системы"&gt;
 Функциональность поисковой системы
 &lt;a class="heading-link" href="#%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%be%d0%bd%d0%b0%d0%bb%d1%8c%d0%bd%d0%be%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d0%b8%d1%81%d0%ba%d0%be%d0%b2%d0%be%d0%b9-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%8b"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Но для начала было бы неплохо конкретизировать, что именно может и для каких целей используется наша поисковая система.&lt;/p&gt;</description></item><item><title>Линейный счетчик</title><link>https://www.bazhenov.me/blog/2012/12/12/linear-counter.html</link><pubDate>Wed, 12 Dec 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/12/12/linear-counter.html</guid><description>&lt;p&gt;Допустим, вам необходимо рассчитать количество уникальных строк в файле. Причем, файл большой – миллионы или десятки миллионов строк. Типичный shell&amp;rsquo;овский однострочник который позволяет решить эту задачу выглядит следующим образом:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sort | uniq | wc -l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И все бы хорошо, но есть одна проблема. Имя ей &lt;code&gt;sort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Сортировка $O(n \log n)$ по времени и $O(n)$ по памяти, поэтому время её работы очень быстро перерастает все разумные пределы. Как вариант, можно хранить не сами строки, а их контрольные суммы. Это снизит как требования по памяти, так и асимптотическую оценку по времени до $O(n)$. Но хранение контрольных сумм подразумевает наличие коллизий, поэтому вы можете получить не точную оценку, а приблизительную. В случаях когда приблизительной оценки достаточно мы можем разменять точность алгоритма на его скорость и требования к памяти.&lt;/p&gt;</description></item><item><title>Feature selection в алгоритмах классификации</title><link>https://www.bazhenov.me/blog/2012/12/10/feature-selection.html</link><pubDate>Mon, 10 Dec 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/12/10/feature-selection.html</guid><description>&lt;p&gt;Существует один очень простой и эффективный способ улучшения алгоритмов классификации, который называется &lt;a href="http://en.wikipedia.org/wiki/Feature_selection" class="external-link" target="_blank" rel="noopener"&gt;feature selection&lt;/a&gt; (выбор классификационных признаков). Этот метод позволяет при построении модели выбрать только самые показательные признаки (например, слова) и отсеять остальные.&lt;/p&gt;
&lt;p&gt;Что такое показательные признаки? Если мы говорим о задаче классификации текстовых документов, то это слова которые несут информацию о классе к которому относится документ. Например, в контексте автомобильной тематики слово &amp;ldquo;Nissan&amp;rdquo;, скорее всего будет показательным признаком, а вот слово &amp;ldquo;новый&amp;rdquo; вряд ли. Использование для классификации не всех слов, а только показательных дает несколько преимуществ.&lt;/p&gt;</description></item><item><title>Толерантный автокомплит</title><link>https://www.bazhenov.me/blog/2012/08/04/autocomplete.html</link><pubDate>Sat, 04 Aug 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/08/04/autocomplete.html</guid><description>&lt;p&gt;Автокомплит вещь удобная. Он позволяет экономить время на наборе текста, когда множество значений поля закрыто. Хороший автокомплит отличается следующими качествами:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;он должен быть быстрый. Если мы хотим экономить силы пользователя, то мы должны ему предложить вариант как можно быстрее;&lt;/li&gt;
&lt;li&gt;он не должен предлагать к вводу варианты которые заведомо неверны;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;он должен быть толерантен к пользовательскому вводу&lt;/em&gt;. В том числе прощать опечатки.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вот о последнем качестве autocomplete алгоритмов я и хочу сегодня поговорить.&lt;/p&gt;</description></item><item><title>Оценка классификатора (точность, полнота, F-мера)</title><link>https://www.bazhenov.me/blog/2012/07/21/classification-performance-evaluation.html</link><pubDate>Sat, 21 Jul 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/07/21/classification-performance-evaluation.html</guid><description>&lt;p&gt;Продолжая тему реализации &lt;a href="https://www.bazhenov.me/blog/2012/06/11/naive-bayes.html" &gt;автоматической классификации&lt;/a&gt; необходимо обсудить следующий очень важный вопрос. Как оценивать качество алгоритма? Допустим, вы хотите внести изменения в алгоритм. Откуда вы знаете что эти изменения сделают алгоритм лучше? Конечно же надо проверять алгоритм на реальных данных.&lt;/p&gt;
&lt;!--excerpt--&gt;
&lt;h2 id="тестовая-выборка"&gt;
 Тестовая выборка
 &lt;a class="heading-link" href="#%d1%82%d0%b5%d1%81%d1%82%d0%be%d0%b2%d0%b0%d1%8f-%d0%b2%d1%8b%d0%b1%d0%be%d1%80%d0%ba%d0%b0"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Основой проверки является тестовая выборка в которой проставлено соответствие между документами и их классами. В зависимости от ваших конкретных условий получение подобной выборки может быть затруднено, так как зачастую ее составляют люди. Но иногда ее можно получить без большого объема ручной работы, если проявить изобретательность. Каких-то конеретных рецептов, к сожалению, не существует.&lt;/p&gt;</description></item><item><title>Наивный байесовский классификатор</title><link>https://www.bazhenov.me/blog/2012/06/11/naive-bayes.html</link><pubDate>Mon, 11 Jun 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/06/11/naive-bayes.html</guid><description>&lt;p&gt;В &lt;a href="https://www.bazhenov.me/blog/2012/06/05/classification.html" &gt;прошлой заметке&lt;/a&gt; я в общих чертах описал задачу классификации, а также традиционные подходы используемые для классификации текстовых документов. В этой заметке я более детально расскажу о том как работает самый простой, но вместе с тем один из самых часто используемых при обработке натуральных языков алгоритм классификации – &lt;a href="http://ru.wikipedia.org/wiki/%d0%9d%d0%b0%d0%b8%d0%b2%d0%bd%d1%8b%d0%b9_%d0%b1%d0%b0%d0%b9%d0%b5%d1%81%d0%be%d0%b2%d1%81%d0%ba%d0%b8%d0%b9_%d0%ba%d0%bb%d0%b0%d1%81%d1%81%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%82%d0%be%d1%80" class="external-link" target="_blank" rel="noopener"&gt;наивный байесовский классификатор&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Заметка разбита на две части: &lt;a href="#theory" &gt;теоретическая&lt;/a&gt;, в которой описаны аспекты классификации, и &lt;a href="#practice" &gt;практическая&lt;/a&gt; часть построения классификатора. Если вы хотите быстро создать прототип классификатора, то обратитесь к практической части заметки, там на приводится пример классификатора. Также на github доступны &lt;a href="https://github.com/bazhenov/naive-bayes-example" class="external-link" target="_blank" rel="noopener"&gt;исходники примера&lt;/a&gt;. Если же вам интересны теоретические принципы работы классификации, то обратитесь к теоретической части заметки.&lt;/p&gt;</description></item><item><title>О задачах классификации</title><link>https://www.bazhenov.me/blog/2012/06/05/classification.html</link><pubDate>Tue, 05 Jun 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/06/05/classification.html</guid><description>&lt;p&gt;В этом и следующих постах, я хочу на пальцах описать процесс создания простого классификатора текстовых документов, а также рассказать о некоторых нетипичных с обывательской точки зрения подходах используемых при классификации документов.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ru.wikipedia.org/wiki/%d0%9a%d0%bb%d0%b0%d1%81%d1%81%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%86%d0%b8%d1%8f_%d0%b4%d0%be%d0%ba%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%be%d0%b2" class="external-link" target="_blank" rel="noopener"&gt;Классификатор&lt;/a&gt; – это алгоритм соотносящий некие входные данные с одним или несколькими классами. В отличие от алгоритмов &lt;a href="http://ru.wikipedia.org/wiki/%d0%9a%d0%bb%d0%b0%d1%81%d1%82%d0%b5%d1%80%d0%bd%d1%8b%d0%b9_%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d0%b7" class="external-link" target="_blank" rel="noopener"&gt;кластеризации&lt;/a&gt; эти классы должны быть определены заранее.&lt;/p&gt;
&lt;p&gt;Возможно, кому-то это определение покажется слишком общими или академическим, поэтому лучше наверное рассмотреть задачу классификации на примерах. А примеров хоть отбавляй.&lt;/p&gt;</description></item><item><title>Особенности функциональщины в Java</title><link>https://www.bazhenov.me/blog/2012/05/12/functional-java.html</link><pubDate>Sat, 12 May 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/05/12/functional-java.html</guid><description>&lt;p&gt;Некоторое время назад мне довелось участвовать в одном из подпроектов целью которого было извлечение упоминаний об автомобилях из произвольного текста с использованием экспертной информации. Это задачу в простонародье называют парсингом :). Так или иначе, этот класс задач имеет свою специфику связанную с относительно большим количеством различных операций над коллекциями. Связано это с необходимостью проверки различных гипотез относительно содержимого анализируемого текста. Оперирование над коллекциями это сильная сторона функциональных языков к которым Java конечно же не относится.&lt;/p&gt;</description></item><item><title>Гармоническое среднее</title><link>https://www.bazhenov.me/blog/2012/05/05/harmonic-mean.html</link><pubDate>Sat, 05 May 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/05/05/harmonic-mean.html</guid><description>&lt;p&gt;Сегодня я хочу обсудить следующую проблему. Как мониторить CPU usage на многопроцессорной машине? Конечно же мониторить метрики выдываемые &lt;code&gt;mpstat&lt;/code&gt;. Эта программа выдает процент времени который процессор проводит в различных состояниях (&lt;code&gt;user&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;, &lt;code&gt;iowait&lt;/code&gt;, &lt;code&gt;idle&lt;/code&gt; и т.д.).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mpstat 1
Linux 2.6.32-200.13.1.el5uek (search-personal2.vfarm.loc)		05/05/2012 	_x86_64_	(16 CPU)

11:35:52 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
11:35:53 AM all 8.34 0.00 0.59 0.06 0.00 0.12 0.00 0.00 90.89
11:35:54 AM all 7.27 0.00 0.86 0.00 0.00 0.36 0.00 0.00 91.51
11:35:55 AM all 7.80 0.00 0.45 0.06 0.00 0.17 0.00 0.00 91.53
11:35:56 AM all 5.33 2.17 0.84 0.00 0.00 0.14 0.00 0.00 91.52
11:35:57 AM all 5.92 0.00 0.40 0.06 0.00 0.06 0.00 0.00 93.57
11:35:58 AM all 4.71 0.07 0.42 0.00 0.00 0.14 0.00 0.00 94.67
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В ретроспективе это выглядит следующим образом:&lt;/p&gt;</description></item><item><title>Один на миллион</title><link>https://www.bazhenov.me/blog/2012/04/16/one-in-a-million.html</link><pubDate>Mon, 16 Apr 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/04/16/one-in-a-million.html</guid><description>&lt;p&gt;Вам наверное приходилось слышать что-то вроде: &amp;ldquo;Этого не может быть. Вероятность этого менее одной миллионной&amp;rdquo;. В бытовом понимании одна миллионная это некая несвершимая вероятность. Другими словами, этого просто не может произойти. Но насколько это вeрятное событие, если вы повторите эксперимент миллион раз? Конечно, вероятность наблюдать событие растет если вы повторяете эксперимент много раз подряд. Но все равно мы зачастую подсознательно пытаемся игнорировать такие события считая их невероятными.&lt;/p&gt;
&lt;p&gt;Тем не менее, в современных Интернет-системах которые обрабатывают миллионы запросов в сутки не заметить в течение дня событие с вероятностью в одну миллионную довольно сложно. И вот почему. Вероятность что интересующее нас событие (с исходной вероятностью &lt;code&gt;1/n&lt;/code&gt;) не проявит себя ни в одном из &lt;code&gt;n&lt;/code&gt; независимых экспериментов равно:&lt;/p&gt;</description></item><item><title>О высокой нагрузке</title><link>https://www.bazhenov.me/blog/2012/02/26/highload.html</link><pubDate>Sun, 26 Feb 2012 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2012/02/26/highload.html</guid><description>&lt;p&gt;В последнее время все чаще говорят о высоконагруженных приложениях. Нельзя не заметить что это теперь очень популярная, можно даже сказать модная, область знаний. Сам же термин &amp;ldquo;высоконагруженная система&amp;rdquo; при этом не имеет в нашей отрасли четкого определения. В этой заметке я хочу привести свои рассуждения по этому вопросу. Я не ставлю перед собой цель дать исчерпывающее определение этого термина. Моя цель, предоставить читателю ключевую информацию о системах такого рода, которая определяет стиль мышления при работе с ними.&lt;/p&gt;</description></item><item><title>Deploy и прочие неприятности</title><link>https://www.bazhenov.me/blog/2011/06/10/deploy.html</link><pubDate>Fri, 10 Jun 2011 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2011/06/10/deploy.html</guid><description>&lt;p&gt;В продолжение &lt;a href="https://www.bazhenov.me/blog/2011/04/09/build.html" &gt;предыдущего поста&lt;/a&gt; хочу немного рассказать о том как у нас происходит deploy. В прошлый раз мы закончили на том что артефакт доставлен на production и готов к развертыванию. Начинается самое интересное, процесс деплоя.&lt;/p&gt;
&lt;!--excerpt--&gt;
&lt;p&gt;Но для начала надо немного описать платформу на которую мы деплоим наши приложения. В качестве servlet-container&amp;rsquo;а мы используем &lt;a href="http://jetty.codehaus.org/jetty/" class="external-link" target="_blank" rel="noopener"&gt;Jetty&lt;/a&gt;. Есть два основных типа приложений, которые мы пишем и сопровождаем: web-приложения, которые имеют некий web-интерфейс (это может быть как UI, так и REST интерфейс), а также background сервисы, которые как правило работают асинхронно (мы активно используем &lt;a href="http://activemq.apache.org/" class="external-link" target="_blank" rel="noopener"&gt;ActiveMQ&lt;/a&gt;). И здесь нужно подметить первую особенность, мы используем Jetty для обоих типов приложений. Это может показатся странным, так как для background-сервисов мы получаем явный overhead связанный с запуском и работой servlet-container&amp;rsquo;а. Но этот overhead просто мизерный по сравнению с тем какие плюсы мы получаем. А именно:&lt;/p&gt;</description></item><item><title>Fair lock</title><link>https://www.bazhenov.me/blog/2011/04/17/fair-lock.html</link><pubDate>Sun, 17 Apr 2011 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2011/04/17/fair-lock.html</guid><description>&lt;p&gt;Не так давно у нас на собеседовании был кандидат, который произвел довольно хорошее впечатление, поэтому было решено предложить ему более сложную задачу, которую обычно мы не спрашиваем. Вот ее немного видоизмененный вариант.&lt;/p&gt;
&lt;p&gt;Переделайте следующий код оставив его многопоточным таким образом, чтобы лампочки зажигались и гасли строго по очереди и в любой момент времени должна быть включена только одна лампочка:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e0def4;background-color:#191724;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c4a7e7"&gt;package&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;me.bazhenov.bulb&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;class&lt;/span&gt; &lt;span style="color:#9ccfd8"&gt;Main&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;static&lt;/span&gt; &lt;span style="color:#31748f"&gt;void&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;main&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;String&lt;/span&gt;&lt;span style="color:#908caa"&gt;[]&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;args&lt;/span&gt;&lt;span style="color:#908caa"&gt;)&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;new&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Thread&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#31748f"&gt;new&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Bulb&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;&amp;#34;first&amp;#34;&lt;/span&gt;&lt;span style="color:#908caa"&gt;)).&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;start&lt;/span&gt;&lt;span style="color:#908caa"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;new&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Thread&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#31748f"&gt;new&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Bulb&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#f6c177"&gt;&amp;#34;seconds&amp;#34;&lt;/span&gt;&lt;span style="color:#908caa"&gt;)).&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;start&lt;/span&gt;&lt;span style="color:#908caa"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;class&lt;/span&gt; &lt;span style="color:#9ccfd8"&gt;Bulb&lt;/span&gt; &lt;span style="color:#31748f"&gt;implements&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Runnable&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;private&lt;/span&gt; &lt;span style="color:#31748f"&gt;final&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;String&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;name&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;Bulb&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;String&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;name&lt;/span&gt;&lt;span style="color:#908caa"&gt;)&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;this&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;name&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;name&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;void&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;run&lt;/span&gt;&lt;span style="color:#908caa"&gt;()&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#ebbcba"&gt;Thread&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;self&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;currentThread&lt;/span&gt;&lt;span style="color:#908caa"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;while&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#908caa"&gt;!&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;self&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;isInterrupted&lt;/span&gt;&lt;span style="color:#908caa"&gt;())&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#ebbcba"&gt;System&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;out&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;println&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;name&lt;/span&gt; &lt;span style="color:#908caa"&gt;+&lt;/span&gt; &lt;span style="color:#f6c177"&gt;&amp;#34; bulb is on&amp;#34;&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#31748f"&gt;try&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#ebbcba"&gt;sleep&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;300&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#908caa"&gt;}&lt;/span&gt; &lt;span style="color:#31748f"&gt;catch&lt;/span&gt; &lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;InterruptedException&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;e&lt;/span&gt;&lt;span style="color:#908caa"&gt;)&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#ebbcba"&gt;self&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;interrupt&lt;/span&gt;&lt;span style="color:#908caa"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#ebbcba"&gt;System&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;out&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;println&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;name&lt;/span&gt; &lt;span style="color:#908caa"&gt;+&lt;/span&gt; &lt;span style="color:#f6c177"&gt;&amp;#34; bulb is off&amp;#34;&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Кандидат предложил использовать &lt;a href="http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html" class="external-link" target="_blank" rel="noopener"&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;&lt;/a&gt; в &lt;code&gt;FairSync&lt;/code&gt; режиме. В первом приближении эта идея может показаться рабочей. Передать общий лок в оба оъекта типа Bulb и синхронизироватся там на нем. Тем не менее, этот подход не работает. Если мы заглянем в документацию к классу, то увидим следующее описание:&lt;/p&gt;</description></item><item><title>Маленький Билд и его друзья</title><link>https://www.bazhenov.me/blog/2011/04/09/build.html</link><pubDate>Sat, 09 Apr 2011 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2011/04/09/build.html</guid><description>&lt;p&gt;Помните фильм &amp;ldquo;Пятый элемент&amp;rdquo;? Там была сцена, когда Зорг опрокидывает стакан на пол и роботы тут же начинают уборку помещения. Всего лишь одно маленькое действие привело в жизнь десяток машин, которые сразу же начали подметать и мыть полы, а в конце еще и налили воды хозяину.&lt;/p&gt;
&lt;p&gt;Что-то похожее происходит в коллективе с налаженным build процессом, когда разработчик коммитит изменения в систему контроля версий.&lt;/p&gt;
&lt;p&gt;О пользе налаженного процесса билда известно много. Но &amp;ldquo;путь на production&amp;rdquo; не прост. После того как код написан и перед тем как он будет запущен на production&amp;rsquo;е было бы неплохо сделать следующие вещи:&lt;/p&gt;</description></item><item><title>Как я собирал NAS</title><link>https://www.bazhenov.me/blog/2010/11/14/nas.html</link><pubDate>Sun, 14 Nov 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/11/14/nas.html</guid><description>&lt;p&gt;Коллеги давно просили меня описать процесс сборки и настройки своего NAS-сервера. Этим постом я искупаю свою вину. К тому же тема действительно актуальная и, мне кажется, многим будет интересно с какими проблемами я столкнулся, какое железо и софт использовал.&lt;/p&gt;
&lt;p&gt;NAS у меня исполняет несколько обязанностей:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;файловое хранилище &amp;ldquo;жирного&amp;rdquo; контента (фильмы, etc);&lt;/li&gt;
&lt;li&gt;сервер для Apple TimeMachine (бекапы);&lt;/li&gt;
&lt;li&gt;качает и раздает торренты;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;самопальный&amp;rdquo; мониторинг сетевой активности с использованием &lt;a href="http://www.mrtg.org/rrdtool/" class="external-link" target="_blank" rel="noopener"&gt;rrdtool&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;локальный git-репозиторий.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Мой опыт использования NAS начался с &lt;a href="http://www.qnap.com/pro_detail_feature.asp?p_id=92" class="external-link" target="_blank" rel="noopener"&gt;QNAP TS-109 PRO II&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>HighLoad++ 2010 - впечатления</title><link>https://www.bazhenov.me/blog/2010/10/31/highload-2010.html</link><pubDate>Sun, 31 Oct 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/10/31/highload-2010.html</guid><description>&lt;p&gt;В этом году я побывал на &lt;a href="http://www.highload.ru/" class="external-link" target="_blank" rel="noopener"&gt;HighLoad++&lt;/a&gt;. Event довольно интересный, поэтому я попытаюсь вкратце описать свои впечатления, а так же основные тенденции наблюдаемые на конференции.&lt;/p&gt;
&lt;p&gt;Во-первых, стоит отметить, что &lt;a href="http://ontico.ru/vita/p/2010/hl-abstracts-2010.pdf" class="external-link" target="_blank" rel="noopener"&gt;тезисы докладов&lt;/a&gt; и &lt;a href="http://ontico.ru/vita/p/2010/hl-presentations-2010.rar" class="external-link" target="_blank" rel="noopener"&gt;презентации&lt;/a&gt; доступны на официальном сайте конференции.&lt;/p&gt;
&lt;p&gt;Я живу во Владивостоке, поэтому мне пришлось пролететь очень большое расстояние чтобы попасть на конференцию. Этим частично обусловлено мое отношение к конференции как к таковой.&lt;/p&gt;
&lt;p&gt;Начнем с приятного. На конференции действительно были специалисты с которыми было интересно общаться. Чувствовалось что люди знают о чем говорят и эту информацию они получили не из мануалов в интернете, а из своей ежедневной практики.&lt;/p&gt;</description></item><item><title>Keep it simple, stupid</title><link>https://www.bazhenov.me/blog/2010/08/30/keep-it-simple-stupid.html</link><pubDate>Mon, 30 Aug 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/08/30/keep-it-simple-stupid.html</guid><description>&lt;p&gt;Простота. Краеугольный камень нашей профессии. Наверняка вам приходилось слышать от своих коллег: “это можно сделать гораздо проще”. Или вы говорили это вашим коллегам: “смотри, можно сделать так. Это ведь гораздо проще”, а в ответ получали взгляд полный непонимания, как бы говорящий вам: “и это ты считаешь проще?”.&lt;/p&gt;
&lt;p&gt;В программной инженерии определенно &lt;em&gt;произошла инфляция&lt;/em&gt; слова “простота”.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.bazhenov.me/images/keep-it-simple-stupid/find-x.gif" alt="Find X"&gt;&lt;/p&gt;
&lt;h2 id="простота--это-расстояние"&gt;
 Простота – это расстояние
 &lt;a class="heading-link" href="#%d0%bf%d1%80%d0%be%d1%81%d1%82%d0%be%d1%82%d0%b0--%d1%8d%d1%82%d0%be-%d1%80%d0%b0%d1%81%d1%81%d1%82%d0%be%d1%8f%d0%bd%d0%b8%d0%b5"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Не существует общепринятого определения простоты. Тем не менее, если мы заглянем в словарь то увидим, что очень часто рядом со словом простота фигурируют такие понятия как: “предсказуемость”, “прямолинейность”, “ясность”, “очевидность”.&lt;/p&gt;</description></item><item><title>Lock vs. Lease</title><link>https://www.bazhenov.me/blog/2010/08/10/lock-vs-lease.html</link><pubDate>Tue, 10 Aug 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/08/10/lock-vs-lease.html</guid><description>&lt;p&gt;Представьте себе типичную задачу, есть поток событий и этот поток событий надо разделить между несколькими пользователями системы. Типичный пример: модерация. Скажем, есть три модератора, которые просматривают добавляемый пользователями контент (допустим рекламные кампании). Мы хотим &amp;ldquo;распилить&amp;rdquo; поток событий между модераторами, чтобы они не делали одну и ту же работу дважды.&lt;/p&gt;
&lt;p&gt;В самом простом случае, мы можем использовать mq в любом его проявлении. Пользователи просто берут сообщение из головы и обрабатывают его. Эта схема хорошо работает, но к сожалению не всегда применима. Например, если пользователи имеют возможность указывать критерии событий которые хотят обрабатывать. Последнее требование очень часто в том или ином виде всплывает в подобных задачах, потому что люди (точно так же, как и процессоры) плохо переносят context switch. Например, если я настроился на модерацию авто тематики, то я фигурально выражаясь загрузил в кеш ключевые слова относящиеся к этой тематике и буду очень расстроен если мне подсунут объект с тематикой относящийся к сотовым телефонам.&lt;/p&gt;</description></item><item><title>About motivation</title><link>https://www.bazhenov.me/blog/2010/06/05/about-motivation.html</link><pubDate>Sat, 05 Jun 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/06/05/about-motivation.html</guid><description>&lt;p&gt;Does anybody know why we do what we do? Why do we wake up everyday and go to our workplaces? It seems that the most obvious reason is money. We need money to function in the society. We need some funds to make some plans, if you wish.&lt;/p&gt;
&lt;p&gt;It turns out that not only money motivate people to do their job. OSS is the proof. Well, yes, we can make money from open source projects. And a lot of companies do this already, but it&amp;rsquo;s not the point. The point is that there is another force motivating people. Most good programmers like some of my colleagues and buddies work not because of money, but because they feel passion to write programs. Money is a &lt;em&gt;required but not sufficient&lt;/em&gt; part of motivation.&lt;/p&gt;</description></item><item><title>ldt или нагрузочное тестирование по-простому</title><link>https://www.bazhenov.me/blog/2010/04/16/ldt.html</link><pubDate>Fri, 16 Apr 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/04/16/ldt.html</guid><description>&lt;p&gt;И снова про инструменты разработки. Часто бывает необходимо сравнить производительность/пропускную способность того или иного участка кода, а писать тестирующий код ой как не хочется. А ведь надо всего-то, запустить нужный метод N раз и померять время выполнения.&lt;/p&gt;
&lt;p&gt;Вот сегодня у меня возник вопрос. Сколько процессору надо времени, чтобы проитерироваться по массиву с заданной длинной?&lt;/p&gt;
&lt;p&gt;Недолго думая, пишем простой POJO класс описывающий тестовый случай.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e0def4;background-color:#191724;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c4a7e7"&gt;package&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;com.blogspot.dotsid.ldt&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;class&lt;/span&gt; &lt;span style="color:#9ccfd8"&gt;ArrayIterationTest&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;private&lt;/span&gt; &lt;span style="color:#31748f"&gt;int&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;size&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;private&lt;/span&gt; &lt;span style="color:#31748f"&gt;int&lt;/span&gt;&lt;span style="color:#908caa"&gt;[]&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;data&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;void&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;setSize&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#31748f"&gt;int&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;size&lt;/span&gt;&lt;span style="color:#908caa"&gt;)&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;this&lt;/span&gt;&lt;span style="color:#908caa"&gt;.&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;size&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;size&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;void&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;prepare&lt;/span&gt;&lt;span style="color:#908caa"&gt;()&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#ebbcba"&gt;data&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#31748f"&gt;new&lt;/span&gt; &lt;span style="color:#31748f"&gt;int&lt;/span&gt;&lt;span style="color:#908caa"&gt;[&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;size&lt;/span&gt;&lt;span style="color:#908caa"&gt;]&lt;/span&gt;&lt;span style="color:#908caa"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#31748f"&gt;public&lt;/span&gt; &lt;span style="color:#31748f"&gt;void&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;doTest&lt;/span&gt;&lt;span style="color:#908caa"&gt;()&lt;/span&gt; &lt;span style="color:#908caa"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#31748f"&gt;for&lt;/span&gt; &lt;span style="color:#908caa"&gt;(&lt;/span&gt; &lt;span style="color:#31748f"&gt;int&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;i&lt;/span&gt; &lt;span style="color:#908caa"&gt;:&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;data&lt;/span&gt; &lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#908caa"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;компилируем исходник и находясь в classpath&amp;rsquo;е выполняем:&lt;/p&gt;</description></item><item><title>Программисты и железо</title><link>https://www.bazhenov.me/blog/2010/03/20/hardware.html</link><pubDate>Sat, 20 Mar 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/03/20/hardware.html</guid><description>&lt;p&gt;Не так давно у нас на работе (Виктор, Игорь, Олег привет вам) состоялась дискуссия на тему: должны ли программисты знать как работает железо на котором выполняются их программы? И я еще раз убедился в том, что большинство программистов придерживаются мнения: &amp;ldquo;железо само по себе, а я сам по себе&amp;rdquo;. Точка зрения вполне ожидаемая и ничего принципиально неправильного в ней нет, но я хотел бы &amp;ldquo;копнуть глубже&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Вообще, мне кажется вопрос &amp;ldquo;стоит ли программистам изучать железо&amp;rdquo; в чем-то похож на вопрос &amp;ldquo;стоит ли программистам изучать математику&amp;rdquo;, — ответ неоднозначен. Существует множество вопросов, ответы на которые могут повлиять на окончательное решение: в какой предметной области вы работаете, насколько эти конкретные знания ценны для вас и т.д. Это вопрос &lt;a href="http://ru.wikipedia.org/wiki/%d0%9e%d0%ba%d1%83%d0%bf%d0%b0%d0%b5%d0%bc%d0%be%d1%81%d1%82%d1%8c_%d0%b8%d0%bd%d0%b2%d0%b5%d1%81%d1%82%d0%b8%d1%86%d0%b8%d0%b9" class="external-link" target="_blank" rel="noopener"&gt;инвестиций и прибыли&lt;/a&gt;. В данном случае под инвестициями подразумевается в первую очередь ваше свободное время, а под прибылью — профессиональные навыки и знания, которые позволят вам более эффективно делать вашу работу. Тогда вопрос сводится к следующему: &lt;em&gt;чем изучение железа может помочь нам программистам делать свою работу лучше&lt;/em&gt;?&lt;/p&gt;</description></item><item><title>Superlinear scalability</title><link>https://www.bazhenov.me/blog/2010/02/15/superlinear-scalability.html</link><pubDate>Mon, 15 Feb 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/02/15/superlinear-scalability.html</guid><description>&lt;p&gt;Как вы думаете во сколько раз может быть быстрее ваша программа, если вам дадут в два раза более &amp;ldquo;крутое&amp;rdquo; железо: в два раза более быстрый процессор, в два раза больше памяти и т.д. Интуитивный ответ — в два раза. Раньше я уже &lt;a href="https://www.bazhenov.me/blog/2009/01/13/moores-law-a-la-finita.html" &gt;писал&lt;/a&gt; о том, что не все так безоблачно. Взвесив все аргументы вы можете сказать: &amp;ldquo;окей, &lt;em&gt;максимум&lt;/em&gt; в два раза&amp;rdquo;. Но что если бы я вам сказал, что при увеличении вычислительной мощности в два раза вы можете получить ускорение &lt;em&gt;больше чем в два раза&lt;/em&gt;?&lt;/p&gt;</description></item><item><title>Миграция ключей</title><link>https://www.bazhenov.me/blog/2010/01/20/keys-migration.html</link><pubDate>Wed, 20 Jan 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/01/20/keys-migration.html</guid><description>&lt;p&gt;Сегодня в разговоре с одним &lt;a href="http://zerkms.livejournal.com/" class="external-link" target="_blank" rel="noopener"&gt;знакомым&lt;/a&gt; всплыл следующий вопрос. В случае, если для дистрибуции ключей по нодам кластера используется типичная схема остатка от деления на количество серверов, какая доля ключей осуществляют миграцию, если один из серверов выводится из схемы? Интуитивным ответом является: &amp;ldquo;почти все&amp;rdquo; или &amp;ldquo;большинство&amp;rdquo;. Тем не менее, если вы любите тренировать мозг, то вот вам небольшая задачка имеющая приложение в web-программировании.&lt;/p&gt;
&lt;p&gt;Формально говоря: при заданном количестве серверов $ N $ и хеширующей функции $ ƒ(x) $ обладающей выходным множеством с мощностью $ P $ ($ \log(P) $ бит, для crc32 $ P = 2^{32} $, для md5 $ P = 2^{128} $) какое количество ключей осуществит миграцию в случае, если серверов станет $ N-1 $, а для дистрибуции ключей используется значение $ f(x) % N $.&lt;/p&gt;</description></item><item><title>Слежка за логами</title><link>https://www.bazhenov.me/blog/2010/01/17/logwatcher.html</link><pubDate>Sun, 17 Jan 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/01/17/logwatcher.html</guid><description>&lt;p&gt;Раньше я уже &lt;a href="https://www.bazhenov.me/blog/2009/04/23/groovy-remote-shell.html" &gt;писал&lt;/a&gt; о том, что нам приходится разрабатывать дополнительный инструментарий для себя. Еще одна сфера которую над которой мы плодотворно поработали — это логгирование. Здесь я не буду говорить о пользе логгирования и о том как надо логгировать. В интернете полно информации по этим аспектам. Я хочу рассказать о том, как мы анализируем логи.&lt;/p&gt;
&lt;p&gt;Дело в том, что в сутки у нас генерируется порядка 100 мегабайт логов. Часть из этой информации — это информация об ошибках (при средней длине сообщения в 5 килобайт нам достаточно 4 секунд чтобы набрать мегабайт информации), часть это аудиторская информация. Просматривать такой объем информации в виде текстового файла — это просто нереально, поэтому мы создали для себя инструмент позволяющий аггрегировать информацию со всех компонентов системы и производить поиск по ней.&lt;/p&gt;</description></item><item><title>KV-хранилища</title><link>https://www.bazhenov.me/blog/2010/01/16/kv-storages.html</link><pubDate>Sat, 16 Jan 2010 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2010/01/16/kv-storages.html</guid><description>&lt;p&gt;В последнее время в web-программировании появился очередной тренд — Key-Value базы данных. Существует просто великое множество KV-решений, — одно лучше другого. Но так ли они важны и какая от них польза? Разрешите мне немного порассуждать о происхождении KV-хранилищ.&lt;/p&gt;
&lt;h2 id="нет-дыма-без-огня"&gt;
 Нет дыма без огня
 &lt;a class="heading-link" href="#%d0%bd%d0%b5%d1%82-%d0%b4%d1%8b%d0%bc%d0%b0-%d0%b1%d0%b5%d0%b7-%d0%be%d0%b3%d0%bd%d1%8f"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Недовольство реляционными базами данных начало появляться давно. Оказалось что на некоторых use case&amp;rsquo;ах они не такие быстрые как хотелось бы. Они слишком сложные для того чтобы большинство программистов понимало как они работают, а следственно и то, как их использовать. Идея изоляции программиста от физических деталей хранения данных с треском провалилась. Если вы не знаете нюансов вашей РСУБД, то эффективно использовать ее на большом dataset&amp;rsquo;е или при высокой конкурентной нагрузке у вас не получится.&lt;/p&gt;</description></item><item><title>IoC контейнеры</title><link>https://www.bazhenov.me/blog/2009/12/21/ioc-containers.html</link><pubDate>Mon, 21 Dec 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/12/21/ioc-containers.html</guid><description>&lt;p&gt;Если вы пишете на объектно-ориентированном языке, то вы должны быть знакомы с &amp;ldquo;джентльменским набором&amp;rdquo; принципов, которые очень полезны при написании кода. К таким принципам относятся: &lt;a href="http://www.objectmentor.com/resources/articles/srp.pdf" class="external-link" target="_blank" rel="noopener"&gt;single responsibility principle&lt;/a&gt;, &lt;a href="http://www.objectmentor.com/resources/articles/ocp.pdf" class="external-link" target="_blank" rel="noopener"&gt;open-closed principle&lt;/a&gt;, &lt;a href="http://www.objectmentor.com/resources/articles/isp.pdf" class="external-link" target="_blank" rel="noopener"&gt;interface segregation principle&lt;/a&gt; и другие. Общий эффект их использования заключается в том, что количество сущностей (классов и интерфейсов) в системе стремительно растет. В этом есть как положительные, так и отрицательные стороны.&lt;/p&gt;
&lt;p&gt;Один из положительных моментов заключается в том, что у каждой сущности появляется строго выделенная роль, для работы которой требуется меньше кода. Такую роль проще протестировать, ее поведение проще понять, а следственно и изменить.&lt;/p&gt;</description></item><item><title>Диагностика OutOfMemoryError подручными средствами</title><link>https://www.bazhenov.me/blog/2009/12/20/out-of-memory-error.html</link><pubDate>Sun, 20 Dec 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/12/20/out-of-memory-error.html</guid><description>&lt;p&gt;Один мой коллега является адептом философии &amp;ldquo;дефолтных настроек&amp;rdquo;. Эта философия пропагандирует следующий подход: не пытайтесь менять environment под свои нужды, — просто научитесь пользоваться стандартным environment&amp;rsquo;ом.&lt;/p&gt;
&lt;p&gt;Несмотря на то что сам по себе этот подход довольно спорен, в нем есть свои плюсы. Умение решать задачи штатными средствами особенно выручает когда необходимо быстро продиагностировать какую-то проблему, а у вас под рукой нет настроенного environment&amp;rsquo;а. Например, вы временно работаете за другой машиной, или географически отдалены от вашего милого сердцу, прекрасно настроенного environment&amp;rsquo;а. Поэтому, я считаю, очень важно уметь диагностировать типовые проблемные ситуации пользуясь только штатными утилитами. Так что давайте посмотрим как мы можем диагностировать memory leak&amp;rsquo;и в java, когда у вас под рукой нет ничего кроме JDK.&lt;/p&gt;</description></item><item><title>Гарантия доставки сообщений и ее последствия</title><link>https://www.bazhenov.me/blog/2009/12/06/delivery-order-guarantee.html</link><pubDate>Sun, 06 Dec 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/12/06/delivery-order-guarantee.html</guid><description>&lt;p&gt;В &lt;a href="https://www.bazhenov.me/blog/2009/11/04/optimistic-locking-application.html" &gt;прошлой заметке&lt;/a&gt;, я затронул тему порядка доставки сообщений MQ-системами. Отсутствие гарантий в отношении этого порядка вызвало некоторое возмущение со стороны читателей, поэтому я решил раскрыть эту тему более полно.&lt;/p&gt;
&lt;p&gt;Почему же многие очереди сообщений не гарантирую порядок? И так ли он вообще важен — этот порядок доставки?&lt;/p&gt;
&lt;h2 id="почему-многие-системы-очередей-не-гарантируют-порядок-доставки"&gt;
 Почему многие системы очередей не гарантируют порядок доставки?
 &lt;a class="heading-link" href="#%d0%bf%d0%be%d1%87%d0%b5%d0%bc%d1%83-%d0%bc%d0%bd%d0%be%d0%b3%d0%b8%d0%b5-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%8b-%d0%be%d1%87%d0%b5%d1%80%d0%b5%d0%b4%d0%b5%d0%b9-%d0%bd%d0%b5-%d0%b3%d0%b0%d1%80%d0%b0%d0%bd%d1%82%d0%b8%d1%80%d1%83%d1%8e%d1%82-%d0%bf%d0%be%d1%80%d1%8f%d0%b4%d0%be%d0%ba-%d0%b4%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b8"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Здесь потребуется договорится об обозначениях.&lt;/p&gt;
&lt;div class="notice note"&gt;
 &lt;div class="notice-title"&gt;
 &lt;i class="fa-solid fa-sticky-note" aria-hidden="true"&gt;&lt;/i&gt;Note
 &lt;/div&gt;
 &lt;div class="notice-content"&gt;Для любых двух событий &lt;code&gt;A&lt;/code&gt; и &lt;code&gt;B&lt;/code&gt; запись &lt;code&gt;A→B&lt;/code&gt; означает, что событие &lt;code&gt;A&lt;/code&gt; происходит перед событием &lt;code&gt;B&lt;/code&gt;. Людям знакомым с &lt;a href="http://en.wikipedia.org/wiki/Java_Memory_Model" class="external-link" target="_blank" rel="noopener"&gt;Java Memory Model&lt;/a&gt; эта запись должна быть известна как отношение happens-before.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Давайте представим себе очередь сообщений, которая гарантирует вышеупомянутый порядок и двух подписчиков читающих сообщения из этой очереди.&lt;/p&gt;</description></item><item><title>Прикладное применение оптимистической блокировки</title><link>https://www.bazhenov.me/blog/2009/11/04/optimistic-locking-application.html</link><pubDate>Wed, 04 Nov 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/11/04/optimistic-locking-application.html</guid><description>&lt;p&gt;В прошлый раз я писал про &lt;a href="https://www.bazhenov.me/blog/2009/10/23/optimistic-locking.html" &gt;оптимистическую блокировку&lt;/a&gt;. Сегодня я хочу описать одну разновидность прикладного применения оптимистической блокировки.&lt;/p&gt;
&lt;p&gt;Это прикладное применение относится к области систем асинхронного обмена сообщений (таких как ActiveMQ, RabbitMQ, OpenMQ, memcacheQ и другие). Очереди сообщений — это очень полезная разновидность промежуточного хранилища данных. В очередь можно положить сообщение и можно из нее взять сообщение. MQ системы позволяют частично решить проблему именуемую &amp;ldquo;&lt;a href="http://en.wikipedia.org/wiki/Producer-consumer_problem" class="external-link" target="_blank" rel="noopener"&gt;Producer—Consumer problem&lt;/a&gt;&amp;rdquo;. Кто-то ложит, а кто-то читает, — все просто. Вообще, подобную систему можно реализовать и поверх вашей любимой реляционной базы данных. Причина, почему существуют очереди сообщений как отдельный тип middleware, заключается в эффективности их реализации. Когда вы знаете, что все что может делать клиент — это писать в хвост и читать с головы, вы можете написать действительно эффективную реализацию с очень большой пропускной способностью. Предыдущее предложение метафорично. Я надеюсь, вы не будете пытаться написать свою mq-систему.&lt;/p&gt;</description></item><item><title>Оптимистическая блокировка</title><link>https://www.bazhenov.me/blog/2009/10/23/optimistic-locking.html</link><pubDate>Fri, 23 Oct 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/10/23/optimistic-locking.html</guid><description>&lt;p&gt;Shared state, как известно необходимо защищать. Иначе параллельные потоки могут его &amp;ldquo;поломать&amp;rdquo;. Это относится и к web-приложениям. Несмотря на отсутствие вменяемой поддержки параллелизма в большинстве web-ориентированных языков (PHP, Python, Ruby), concurrency в web-приложениях хватает. Запросы приходят на web-сервер параллельно, исполняются на разных процессорах параллельно и т.д. По этой причине следующий код некорректен:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e0def4;background-color:#191724;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;$bulletin&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;$manager&lt;/span&gt;&lt;span style="color:#908caa"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;findBulletinById&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;$request&lt;/span&gt;&lt;span style="color:#908caa"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;id&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;$bulletin&lt;/span&gt;&lt;span style="color:#908caa"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;setHits&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;$bulletin&lt;/span&gt;&lt;span style="color:#908caa"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;getHits&lt;/span&gt;&lt;span style="color:#908caa"&gt;()&lt;/span&gt;&lt;span style="color:#908caa"&gt;+&lt;/span&gt;&lt;span style="color:#f6c177"&gt;1&lt;/span&gt; &lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;$manager&lt;/span&gt;&lt;span style="color:#908caa"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;saveBulletin&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;$bulletin&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Два параллельных потока могут одновременно загрузить объявление, одновременно инкрементировать счетчик, и записать объявление обратно. Это приведет к тому, что один инкремент потеряется. В общем случае, если &lt;code&gt;N&lt;/code&gt; потоков выполняют данный код одновременно, может быть потеряно до &lt;code&gt;N - 1&lt;/code&gt; update&amp;rsquo;ов.&lt;/p&gt;</description></item><item><title>Interrupted Exception</title><link>https://www.bazhenov.me/blog/2009/09/04/interrupted-exception.html</link><pubDate>Fri, 04 Sep 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/09/04/interrupted-exception.html</guid><description>&lt;p&gt;Недавно еще раз встретился с некорректной обработкой &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/InterruptedException.html" class="external-link" target="_blank" rel="noopener"&gt;InterruptedException&lt;/a&gt; в java. InterruptedException — это checked exception генерируемый многими методами стандартной библиотеки, которые блокируют поток исполнения. К таким относятся: &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/locks/Lock.html#lockInterruptibly%28%29" class="external-link" target="_blank" rel="noopener"&gt;interruptible версии lock&amp;rsquo;ов&lt;/a&gt;, метод &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#sleep%28long%29" class="external-link" target="_blank" rel="noopener"&gt;Thread.sleep()&lt;/a&gt;, некоторые &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html#take%28%29" class="external-link" target="_blank" rel="noopener"&gt;операции над блокирующими очередями&lt;/a&gt;, некоторые &lt;a href="http://java.sun.com/javase/6/docs/api/java/nio/channels/SocketChannel.html#open%28java.net.SocketAddress%29" class="external-link" target="_blank" rel="noopener"&gt;операции над каналами&lt;/a&gt; и другие.&lt;/p&gt;
&lt;p&gt;По своей сути, &lt;code&gt;InterruptedException&lt;/code&gt; сигнализирует о том, что поток просят завершить его работу. При этом вас не просят &lt;em&gt;немедленно&lt;/em&gt; завершить свою работу. Вас просят &lt;em&gt;корректно&lt;/em&gt; завершить работу. На это может понадобится некоторое время.&lt;/p&gt;</description></item><item><title>Pipelining</title><link>https://www.bazhenov.me/blog/2009/08/01/pipelining.html</link><pubDate>Sat, 01 Aug 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/08/01/pipelining.html</guid><description>&lt;p&gt;Существует одна очень старая и эффективная техника — конвейерная обработка данных (pipelining). Ее смысл заключается в том, что разные физические исполнители, которые могут работать не блокируя друг друга (хвала &lt;a href="http://en.wikipedia.org/wiki/Direct_memory_access" class="external-link" target="_blank" rel="noopener"&gt;DMA&lt;/a&gt;), такие как: процессоры, жесткие диски, сетевые карты, — должны работать не блокируя друг друга. Это позволяет повысить их утилизацию, и, если правильно все организовать, не допустить перегрузки отдельно взятых исполнителей. Отличительной особенностью этой техники является то, что она используется в &lt;a href="http://en.wikipedia.org/wiki/Instruction_pipeline" class="external-link" target="_blank" rel="noopener"&gt;микропроцессорах&lt;/a&gt; с незапамятных времен, и сейчас является неотъемлемой частью любого &lt;a href="http://en.wikipedia.org/wiki/Superscalar" class="external-link" target="_blank" rel="noopener"&gt;суперскалярного процессора&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Возожности mysqlnd в PHP/5.3</title><link>https://www.bazhenov.me/blog/2009/08/01/mysqlnd-php.html</link><pubDate>Sat, 01 Aug 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/08/01/mysqlnd-php.html</guid><description>&lt;p&gt;Если вы не знаете, то с PHP/5.3 поставляется новый mysql драйвер — &lt;a href="http://ru.php.net/mysqli.mysqlnd" class="external-link" target="_blank" rel="noopener"&gt;mysqlnd&lt;/a&gt;. У него есть несколько особенностей и воможностей, которые отличают его от libmysql.&lt;/p&gt;
&lt;p&gt;Первое не очень интерестно. Теперь при fetch&amp;rsquo;e результата не происходит копирования из памяти libmysql в память, находящуюся под управлением zend engine. Фактически весь result set находится в памяти zend engine. Это значит что выборки превышающие по размеру memory limit теперь таки будут генерировать out of memory. Наверное, это представляет ценность для владельцев shared хостинга, но для тех у кого выделенный сервер это имеет мало пользы.&lt;/p&gt;</description></item><item><title>О проблемах растущего размера</title><link>https://www.bazhenov.me/blog/2009/08/01/scaling-vectors.html</link><pubDate>Sat, 01 Aug 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/08/01/scaling-vectors.html</guid><description>&lt;p&gt;Все таки интернет индустрия развивается. Теперь на каждом углу высоконагруженные проекты, миллионы пользователей, требования к high-availability, масштабиремости. Причем вот ведь странно. К масштабиремости всегда относятся как-то однобоко. Иногда ее путают с производительностью. А иногда не понимают что масштабируют.&lt;/p&gt;
&lt;p&gt;Dan Pritchett, один из архитекторов eBay (теперь уже бывший), еще в 2006 году написал отличное эссе &lt;em&gt;You scaled your what?&lt;/em&gt; на тему векторов масштабирования (scaling vectors)&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. Действительно, существует масса направлений которые требуют внимания при интенсивном росте проекта, а следственно и сложности решаемых в проекте проблем. А это значит, что употребляя слово &amp;ldquo;масштабируемость&amp;rdquo;, мы должны отдавать себе отчет в том, в каком контексте мы употребляем это слово.&lt;/p&gt;</description></item><item><title>Что если цепь рванет?</title><link>https://www.bazhenov.me/blog/2009/08/01/cache.html</link><pubDate>Sat, 01 Aug 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/08/01/cache.html</guid><description>&lt;p&gt;Сегодня со мной произошел форс-мажор. Я приехал на работу на велосипеде так что, когда рабочий день закончился, я сел на вел и сопровождаемый прохладным ветерком покатил в центр города. Далеко уехать не получилось. Буквально через 40-50 метров я услышал хруст и педаль под ногой резко провалилась. Оказалось, что я поломал крепление заднего переключателя.&lt;/p&gt;
&lt;p&gt;Вообще, поломать крепление заднего переключателя еще надо умудрится. Переключатель не испытывает больших нагрузок (разве что в момент переключения), так как находится на прямом ходу цепи. На прямом ходу цепь практически расслаблена, — основную нагрузку она испытывает на обратном ходу проходя через заднюю звезду. При ближайшем рассмотрении оказалось, что всему виной цепь. Разорвавшись она застряла в транке переключателя (цепь проходит через ритейнер переключателя по змейке) как раз в тот момент когда я в очередной раз перенес вес тела на педаль.&lt;/p&gt;</description></item><item><title>Энди и Билл</title><link>https://www.bazhenov.me/blog/2009/07/19/Andy-and-Bill.html</link><pubDate>Sun, 19 Jul 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/07/19/Andy-and-Bill.html</guid><description>&lt;p&gt;Вчера моя девушка купила себе Sims 3. Ну вы знаете&amp;hellip; Маленькие человечки, которые постоянно требуют спать и есть. Эдакие тамагочи, которым хватает вычислительной мощности чтобы обсчитывать нравятся ли им их соседи, босс и прическа того волосатого парня, который косится на них в течении всей вечеринки. Полторы тысячи за лицензионную копию. И на обороте бокса вы можете прочитать:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Системные требования CPU: (XP) процессор P4 с частотой 2.0 ГГц или аналогичный: (Vista) процессор с частотой 2.4 ГГц или аналогичный. RAM: (XP) 1 Гб оперативной памяти: (Vista) 1.5 Гб оперативной памяти.&lt;/p&gt;</description></item><item><title>Fail Fast</title><link>https://www.bazhenov.me/blog/2009/07/15/fail-fast.html</link><pubDate>Wed, 15 Jul 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/07/15/fail-fast.html</guid><description>&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e0def4;background-color:#191724;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ebbcba"&gt;$data&lt;/span&gt; &lt;span style="color:#908caa"&gt;=&lt;/span&gt; &lt;span style="color:#ebbcba"&gt;file_get_contents&lt;/span&gt;&lt;span style="color:#908caa"&gt;(&lt;/span&gt;&lt;span style="color:#ebbcba"&gt;$location&lt;/span&gt;&lt;span style="color:#908caa"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Что не так с этим кодом? На первый взгяд все хорошо. Вряд ли он может нам чем-нибудь навредить.&lt;/p&gt;
&lt;p&gt;Хорошо, предположим, что у вас есть 3 web frontend&amp;rsquo;а, каждый из которых может обслуживать 60 параллельных запросов (итого 180 конкурентных запросов). На минутку предположим, что вышеприведенный код — это единственный код, который выполняется при обработке запроса. Если location указывает на локальный ресурс (на локальной файловой системе), то вряд ли что-то может пойти не так. Latency чтения с локальной файловой системы достаточно низкий для того, чтобы не беспокоится о возможных проблемах (если файлы достаточно маленькие).&lt;/p&gt;</description></item><item><title>Perfomance vs. scalability</title><link>https://www.bazhenov.me/blog/2009/06/28/performance-versus-scalability.html</link><pubDate>Sun, 28 Jun 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/06/28/performance-versus-scalability.html</guid><description>&lt;p&gt;Иногда встречаюсь c непониманием того, что такое производительность, а что такое масштабируемость. Почему-то некоторые люди считают, что это одно и то же.&lt;/p&gt;
&lt;p&gt;С производительностью все более менее понятно. Это мера скорости работы системы. Запрос поступает в систему и через некоторое время система генерирует ответ. Это время (которое иногда называют latency) и является мерой производительности системы. Для интернет-приложений время получения ответа клиентом может быть значительно больше, чем время генерации ответа на стороне сервера (потери в канале, необходимость загрузки дополнительных статических ресурсов и т.д). Обычно эти издержки не учитываются при оценке производительности, хотя надо признать, они могут очень сильно влиять на user experience работы с приложением.&lt;/p&gt;</description></item><item><title>Future Evolution of High-Performance Microprocessors</title><link>https://www.bazhenov.me/blog/2009/06/27/future-evolution-of-microprocessors.html</link><pubDate>Sat, 27 Jun 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/06/27/future-evolution-of-microprocessors.html</guid><description>&lt;p&gt;На просторах сети нашел довольно &lt;a href="http://www.youtube.com/watch?v=BBMeplaz0HA" class="external-link" target="_blank" rel="noopener"&gt;интерестное видео&lt;/a&gt; о тенденциях развития микропроцессоров. Norm Jouppi из Hewlett-Packard рассказывает о текущих проблемах и о том, что из себя будут представлять микропроцессоры лет эдак через 5-10.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/BBMeplaz0HA?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;Было много сказано, про power wall и про то, как растущее энергопотребление не дает наращивать частоты. При этом заметно упали темпы снижения базового напряжения, используемого микросхемами. Мне, как программисту, было интерестно в первую очередь другое, — каковы тенденции в развитии микропроцессоров.&lt;/p&gt;</description></item><item><title>Groovy Remote Shell</title><link>https://www.bazhenov.me/blog/2009/04/23/groovy-remote-shell.html</link><pubDate>Thu, 23 Apr 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/04/23/groovy-remote-shell.html</guid><description>&lt;p&gt;Я работаю в довольно интенсивно развивающемся проекте. Мы много эксперементируем с разными инструментами. Иногда приходится инструменты разрабатывать самим.&lt;/p&gt;
&lt;p&gt;Последний инструментарий, который мне пришлось реализовать самому — это удаленный groovy shell. Если вы незнакомы с &lt;a href="http://groovy.codehaus.org/" class="external-link" target="_blank" rel="noopener"&gt;groovy&lt;/a&gt;, то скажу, что это динамический язык работающий на JVM.&lt;/p&gt;
&lt;p&gt;Задачей было разработать инструментарий, который бы позволил удаленно дергать некий служебный функционал внутри приложения (запускать переиндексацию, менять настройки thread pool&amp;rsquo;ов, удалять или создавать обьекты в БД и т.д.). Сначала для этих целей мы использовали JMX. Оказалось слишком сложно и неудобно. Решили сделать удаленный shell, который бы позволял выполнять groovy код в адресном пространстве приложения, что называется, на лету. Что может быть проще, чем получить ссылку на фасад, загрузить пару обьектов и послать им пару сообщений, – прямой канал с приложением в обход всех web-интерфейсов.&lt;/p&gt;</description></item><item><title>Конец эры закона Мура</title><link>https://www.bazhenov.me/blog/2009/01/13/moores-law-a-la-finita.html</link><pubDate>Tue, 13 Jan 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/01/13/moores-law-a-la-finita.html</guid><description>&lt;p&gt;Начиная с 70-х годов прошлого века производители микропроцессоров осуществляли экспоненциальный рост производительности, описанный законом Мура. Но достигнув физических ограничений, связанных с резким скачком тока утечки транзисторов и, как следствие, рассеивания тепла, стало понятно — дальнейшее увеличение производительности процессоров существующими техниками невозможно. Еще в 2003 году Intel обещала предоставить 4 ГГц модель. И вроде бы годом позже Intel&amp;rsquo;овцы приблизились к реализации задуманного, — появился процессор с тактовой частотой 3.8 ГГц. Но 4 гигагерцовым &amp;ldquo;мечтам&amp;rdquo; так и не суждено было сбыться. А все современные модели процессоров работают на тактовой частоте до 3 ГГц. Индустрия, как мы все теперь знаем, пошла другим путем. Выходом стало увеличение количества процессоров (ядер).&lt;/p&gt;</description></item><item><title>16x16</title><link>https://www.bazhenov.me/blog/2009/01/09/16x16.html</link><pubDate>Fri, 09 Jan 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/01/09/16x16.html</guid><description>&lt;p&gt;Это скриншот с Windows 2008 R2 с запущенным на нем SQLServer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.bazhenov.me/images/16x16/256.jpg" alt="256 core taskmanager"&gt;&lt;/p&gt;
&lt;p&gt;Примечательна сама загрузка. Загрузить 256 ядер почти на полную одним приложением не так-то просто. У MySQL, например, проблемы начинаются уже с 8 ядрами&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. У нас в проекте мы это испытали на собственной шкуре.&lt;/p&gt;
&lt;p&gt;Как заметил Doug Holland, для того чтобы наблюдать такие полотна графиков, надо иметь по меньшей мере 30&amp;quot; монитор&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;. Task manager плохо масштабируется по колличеству ядер, если вам угодно :).&lt;/p&gt;</description></item><item><title>Enhanced null handling в Java</title><link>https://www.bazhenov.me/blog/2009/01/09/null-handling.html</link><pubDate>Fri, 09 Jan 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/01/09/null-handling.html</guid><description>&lt;p&gt;Как показало голосование по вопросу java 7 language changes&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;, null-handling в java - это самый большой &amp;ldquo;pain in the ass&amp;rdquo; из всех, через которые Java заставляет проходить программистов. С другой стороны то-же голосование на devoxxx по вопросу самого популярного языка под JVM, показало, что это Groovy.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://chart.apis.google.com/chart?cht=p&amp;amp;chd=t:49,30,14,10,5,4,5,17&amp;amp;chds=0,49&amp;amp;chs=350x200&amp;amp;chl=Groovy%7CScala%7CJRuby%7CJython%7CFan%7CPHP%7CClojure%7CDon%27t+care&amp;amp;chp=3.14" alt="Результаты голосования"&gt;&lt;/p&gt;
&lt;p&gt;Видимо, все те, кто привыкли к &lt;a href="http://groovy.codehaus.org/Operators#Operators-ElvisOperator%28%3F%3A%29" class="external-link" target="_blank" rel="noopener"&gt;оператору Элвиса&lt;/a&gt; и &lt;a href="http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator%28%3F.%29" class="external-link" target="_blank" rel="noopener"&gt;safe-navigate&lt;/a&gt; в groovy, пришли на devoxxx и устроили флеш моб. Вобщем приветствуйте. Proposal&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; определяет 2 новых оператора в языке: &lt;code&gt;null-safe&lt;/code&gt; и &lt;code&gt;null-default&lt;/code&gt;. Работает так же как и в groovy. Просто и понятно.&lt;/p&gt;</description></item><item><title>Terracotta vs. Memcache</title><link>https://www.bazhenov.me/blog/2009/01/09/terracotta-vs-memcache.html</link><pubDate>Fri, 09 Jan 2009 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2009/01/09/terracotta-vs-memcache.html</guid><description>&lt;p&gt;В последнее время начали сравнивать &lt;code&gt;terracotta&lt;/code&gt; и &lt;code&gt;memcache&lt;/code&gt;. Мне это сравнение кажется некорректным. Бытует мнение что &lt;code&gt;terracotta&lt;/code&gt; — это distributed cache&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. Это все равно что называть автомобиль &amp;ldquo;четырехколесным мопедом&amp;rdquo;, только потому, что он может ездить и у него четыре колеса.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Terracotta&lt;/code&gt; часто определяют как Network Attached Memory. И это правда, но не вся. Технически никто не мешает вам использовать &lt;code&gt;terracotta&lt;/code&gt; как distributed (или, как его еще иногда называют, clustered) cache. Но тут возникает проблема с HA. В кластере Terracotta всегда есть координатор, который управляет потоком данных. По словам Ari Zilka&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; (одного из основателей Terracota Inc.), именно по этой причине terracotta очень хорошо масштабируется, так как благодаря наличию координатора нет необходимости использовать multicast передачу данных. Однако, наличие координатора означает single point of failure. При использовании memcache SPOF нету, но вам необходимо самому распределять данные по нодам.&lt;/p&gt;</description></item><item><title>ANTLR и DSL</title><link>https://www.bazhenov.me/blog/2008/06/18/antlr-dsl.html</link><pubDate>Wed, 18 Jun 2008 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2008/06/18/antlr-dsl.html</guid><description>&lt;p&gt;Задача. Есть биллинг, который аккумулирует данные по операциям. Нужно предоставить интерфейс (программный) для получения отчетов. Каждый отчет может быть параметризирован. Например, получить определенный отчет (скажем начисления за месяц) для какого-то конкретного клиента. Список отчетов будет изменятся, будут разрабатываться новые. Учитывая требования, пришел к выводу, что наилучший вариант предоставить клиенту декларативный язык для получения данных. Что-то вроде:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;build DepositReport from '2008-01-01' to '2008-02-01'
	with userId = 15, depositGround = 'cash'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Решил написать грамматику для реализации парсера на &lt;a href="http://www.antlr.org/" class="external-link" target="_blank" rel="noopener"&gt;ANTLR&lt;/a&gt;. К собственному удивлению, справился за пол часа, а результирующая грамматика занимала 35 строчек кода. На выходе я имел следующий интерфейс.&lt;/p&gt;</description></item><item><title>Чайник и сложность ПО</title><link>https://www.bazhenov.me/blog/2008/06/17/boiler.html</link><pubDate>Tue, 17 Jun 2008 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2008/06/17/boiler.html</guid><description>&lt;p&gt;Случайно наткнулся на свой давешний &lt;a href="http://forum.agiledev.ru/index.php?t=msg&amp;amp;goto=5650&amp;amp;#msg_5650" class="external-link" target="_blank" rel="noopener"&gt;пост&lt;/a&gt; основной идеей которого, было то, что все программные модели являются суть упрощением обьектов реального мира. И задача программиста упростить модель настолько насколько это возможно, но не больше. Как жаль, что я сам порой об этом забываю.&lt;/p&gt;</description></item><item><title>MySQL Queue</title><link>https://www.bazhenov.me/blog/2008/06/12/mysql-queue.html</link><pubDate>Thu, 12 Jun 2008 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/blog/2008/06/12/mysql-queue.html</guid><description>&lt;p&gt;Случайно нашел интерестное программное решение. &lt;a href="http://q4m.31tools.com/" class="external-link" target="_blank" rel="noopener"&gt;Q4M&lt;/a&gt; — иммитация сервера очереди сообщений посредством MySQL сервера (начиная с версии 5.1). Написано что &lt;em&gt;fast&lt;/em&gt;, &lt;em&gt;robust&lt;/em&gt; и &lt;em&gt;flexible&lt;/em&gt; (интерестно, бывает что-нибудь одно?). Однако, дозволяются условные выборки из очереди, несмотря на то, что в limitations указано, - индексы при этом не используются.&lt;/p&gt;
&lt;p&gt;Вообще, довольно трудно представить себе где бы могла мне пригодится такая очередь сообщений. Cуществует куча бесплатных специализированных решений, которые создавались специально для обработки очередей сообщений. Взять хотя бы &lt;a href="http://activemq.apache.org/" class="external-link" target="_blank" rel="noopener"&gt;ActiveMQ&lt;/a&gt; или &lt;a href="http://community.jboss.org/wiki/JBossMQ" class="external-link" target="_blank" rel="noopener"&gt;JBossMQ&lt;/a&gt;. Поддержка транзакционности, оптимизирована для быстрой вставки (в принципе, как и любая другая MQ система), поддержка практически всех популярных скриптовых языков посредством &lt;a href="http://stomp.codehaus.org/" class="external-link" target="_blank" rel="noopener"&gt;STOMP&lt;/a&gt;, встроенный &lt;a href="http://activemq.apache.org/camel/" class="external-link" target="_blank" rel="noopener"&gt;message router&lt;/a&gt;, поддержка репликации, поддержка forward on demand bridge и куча еще чего. Учитывая то, что MQ системы обычно применяются либо при интеграции приложений либо в целях масштабируемости приложений (что говорит о больших обьемах данных), непонятно зачем нужно решение подобное &lt;code&gt;Q4M&lt;/code&gt;. Рано или поздно вы упретесь в пропускную способность sql-сервера по чтению, добавите slave серверов, а затем упретесь в ту же пропускную способность, но уже по записи. И тут уже никакая репликация не спасет.&lt;/p&gt;</description></item><item><title/><link>https://www.bazhenov.me/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/about/</guid><description>&lt;h1 id="about"&gt;
 About
 &lt;a class="heading-link" href="#about"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;Hello 👋&lt;/p&gt;
&lt;p&gt;My name is Denis. I&amp;rsquo;ve been a Software Developer for over 20 years, working with a wide range of technologies for commercial applications and &lt;a href="https://www.bazhenov.me/projects/" &gt;personal projects&lt;/a&gt;. It&amp;rsquo;s tough to list them all, but here are a few of my favorites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Information retrieval applications, particularly Apache Lucene, are my area of expertise. I designed, built, and for many years assisted in operating large scale e-commerce search systems;&lt;/li&gt;
&lt;li&gt;Monitoring, troubleshooting, and application introspection in cloud environments;&lt;/li&gt;
&lt;li&gt;Rust language, application performance analysis and making software faster on modern hardware;&lt;/li&gt;
&lt;li&gt;Java language and JVM in general;&lt;/li&gt;
&lt;li&gt;Linux as an application platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Last 5 years I’ve been playing the role of a technical leader in a development team helping adopt and use the right technologies for the job.&lt;/p&gt;</description></item><item><title/><link>https://www.bazhenov.me/projects/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.bazhenov.me/projects/</guid><description>&lt;h1 id="projects"&gt;
 Projects
 &lt;a class="heading-link" href="#projects"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;Here is the list of open source project I&amp;rsquo;ve developed through the years&amp;hellip;&lt;/p&gt;
&lt;h2 id="tango"&gt;
 &lt;a href="https://github.com/bazhenov/tango" class="external-link" target="_blank" rel="noopener"&gt;Tango&lt;/a&gt;
 &lt;a class="heading-link" href="#tango"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Rust microbenchmarking harness based on &lt;a href="https://www.bazhenov.me/posts/paired-benchmarking/" &gt;paired-testing methodology&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="safe-cargo"&gt;
 &lt;a href="https://github.com/bazhenov/safe-cargo" class="external-link" target="_blank" rel="noopener"&gt;safe-cargo&lt;/a&gt;
 &lt;a class="heading-link" href="#safe-cargo"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;cargo&lt;/code&gt; wrapper that executes all commands within a sandboxed environment safeguards against supply chain attacks when executing untrusted code.&lt;/p&gt;
&lt;h2 id="groovysh-server"&gt;
 &lt;a href="https://github.com/bazhenov/groovy-shell-server" class="external-link" target="_blank" rel="noopener"&gt;Groovysh Server&lt;/a&gt;
 &lt;a class="heading-link" href="#groovysh-server"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Groovy shell embedded in an application and exposed via secure SSH channel. Helps to monitor and diagnose JVM applications using interactive REPL shell.&lt;/p&gt;</description></item></channel></rss>