Привет, Хаброжители! Книга Рикардо Террелли (Riccardo Terrell) дает представление о рекомендуемых методах создания конкурентных и масштабируемых программ в .NET, освещая преимущества функциональной парадигмы и предоставляя соответствующие инструменты и принципы, позволяющие легко и правильно поддерживать конкурентность. В итоге, вооружившись новыми навыками, вы получите знания, необходимые для того, чтобы стать экспертом в предоставлении успешных высокопроизводительных решений.
Если вы пишете многопоточный код на .NET, то эта книга может вам помочь. Если вы заинтересованы в использовании функциональной парадигмы для упрощения конкурентного программирования и максимального повышения производительности приложений, то данная книга станет для вас важным руководством. Она принесет пользу любым разработчикам на .NET, желающим писать конкурентные, реактивные и асинхронные приложения, которые масштабируются и автоматически адаптируются к имеющимся аппаратным ресурсам везде, где бы ни работали такие программы.
Четырнадцать глав этой книги разделены на три части. В части I представлены функциональные концепции конкурентного программирования и описаны навыки, необходимые для понимания функциональных аспектов написания многопоточных программ.
В части II углубленно рассматриваются различные модели конкурентного программирования в функциональной парадигме. Мы изучим такие темы, как библиотека Task Parallel Library (TPL), и реализуем параллельные шаблоны, такие как Fork/Join, «разделяй и властвуй» и MapReduce. В этой части также обсуждаются декларативная компоновка, высокоуровневые абстракции в асинхронных операциях, агентное программирование и семантика передачи сообщений.
В части III показано, как реализовать на практике все функциональные методы конкурентного программирования, изученные в предыдущих главах.
В книге также содержится три приложения.
По сравнению с потоками MailboxProcessor в сочетании с асинхронными рабочими процессами представляет собой простой вычислительный блок (примитив). Агенты могут появляться и уничтожаться с минимальными издержками. Можно распределить работу между несколькими объектами MailboxProcessor аналогично тому, как можно использовать потоки, без дополнительных накладных расходов, связанных с созданием нового потока. Благодаря этому вполне возможно создавать приложения, состоящие из сотен тысяч агентов, работающих параллельно, с минимальной нагрузкой на ресурсы компьютера.
В данном разделе мы воспользуемся несколькими экземплярами MailboxProcessor, чтобы реализовать игру Game of Life (игра «Жизнь») (wiki-англ и wiki-рус»). Согласно «Википедии», Game of Life, говоря простыми словами, является клеточным автоматом. Это игра без игроков — другими словами, когда игра начинается со случайной начальной конфигурации, она выполняется без каких-либо других входных данных. Игра состоит из набора клеток, образующих сетку; в каждой клетке выполняется несколько математических правил. Клетки могут жить, умирать и размножаться. Каждая клетка взаимодействует с восемью соседями (соседними клетками). Для перемещения клеток в соответствии с этими правилами необходимо постоянно вычислять новое состояние сетки.
Game of Life имеет следующие правила:
В зависимости от начальных условий клетки образуют характерные структуры на протяжении всей игры. Посредством многократного применения правил создаются следующие поколения клеток, пока клетки не достигнут стабильного состояния (рис. 11.12).
В листинге 11.9 представлена реализация клетки Game of Life AgentCell, основанная на основе F#-типов MailboxProcessor. Каждая клетка-агент взаимодействует с соседними клетками посредством асинхронной передачи сообщений, создавая, таким образом, полностью распараллеленную Game of Life. Для краткости я опустил некоторые части кода, поскольку они не имеют отношения к основной теме примера. Полную реализацию вы найдете в исходном коде к этой книге, выложенном на сайте издательства.
AgentCell описывает клетку в сетке Game of Life. Основная концепция заключается в том, что каждый агент обменивается информацией с соседними ячейками о своем текущем состоянии посредством асинхронной передачи сообщений. Этот шаблон создает цепочку взаимосвязанных параллельных коммуникаций, которая задействует все клетки, отправляющие свое обновленное состояние агенту MailboxProcessor updateAgent. Получив эти данные, updateAgent обновляет графику в пользовательском интерфейсе (листинг 11.10).
updateAgent, как следует из названия, обновляет состояние каждого пиксела в соответствии со значением клетки, полученным в сообщении Update. Агент поддерживает состояние пикселов и задействует его для создания нового изображения, когда все клетки передадут свое новое состояние. Затем updateAgent обновляет графический пользовательский WPF-интерфейс, применяя это новое изображение, которое соответствует текущей сетке Game of Life:
Важно отметить, что агент updateAgent задействует текущий контекст синхронизации для корректного обновления WPF-контроллера. Текущий поток переключается на поток пользовательского интерфейса с помощью функции Async.SwitchToContext (описана в главе 9).
Последний фрагмент кода для выполнения Game of Life генерирует сетку, которая служит игровой площадкой для клеток, а затем таймер уведомляет клетки о необходимости выполнить обновление (листинг 11.11). В этом примере сетка представляет собой квадрат 100 × 100 клеток, всего 10 000 клеток (объектов MailboxProcessor), которые вычисляются параллельно по таймеру каждые 50 мс, как показано на рис. 11.13. Десять тысяч объектов MailboxProcessor взаимодействуют и обновляют пользовательский интерфейс 20 раз в секунду (код, на который следует обратить внимание, выделен жирным шрифтом).
Уведомления всем клеткам (агентам) рассылаются параллельно, с использованием PLINQ. Клетки представляют собой F#-последовательности, которые рассматриваются как .NET IEnumerable, что позволяет легко интегрировать LINQ/PLINQ.
При выполнении кода программа генерирует 10 000 F#-объектов типа MailboxProcessor менее чем за 1 мс, при этом агенты занимают в памяти менее 25 Мбайт. Впечатляет!
» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок
Для Хаброжителей скидка 20% по купону — Concurrency in .NET
По факту оплаты бумажной версии книги на e-mail высылается электронная версия книги.
Если вы пишете многопоточный код на .NET, то эта книга может вам помочь. Если вы заинтересованы в использовании функциональной парадигмы для упрощения конкурентного программирования и максимального повышения производительности приложений, то данная книга станет для вас важным руководством. Она принесет пользу любым разработчикам на .NET, желающим писать конкурентные, реактивные и асинхронные приложения, которые масштабируются и автоматически адаптируются к имеющимся аппаратным ресурсам везде, где бы ни работали такие программы.
Структура издания: дорожная карта
Четырнадцать глав этой книги разделены на три части. В части I представлены функциональные концепции конкурентного программирования и описаны навыки, необходимые для понимания функциональных аспектов написания многопоточных программ.
- В главе 1 описаны основные понятия и цели конкурентного программирования, а также причины применения функционального программирования для написания многопоточных приложений.
- В главе 2 исследуется ряд технологий функционального программирования для повышения производительности многопоточных приложений. Цель этой главы — предоставить читателю концепции, используемые в остальной книге, и познакомить с мощными идеями, возникающими из функциональной парадигмы.
- В главе 3 дается обзор функциональной концепции неизменяемости. Здесь объясняется, как неизменяемость применяется для написания предсказуемых и корректных конкурентных программ и для реализации функциональных структур данных, которые являются потокобезопасными по своей сути.
В части II углубленно рассматриваются различные модели конкурентного программирования в функциональной парадигме. Мы изучим такие темы, как библиотека Task Parallel Library (TPL), и реализуем параллельные шаблоны, такие как Fork/Join, «разделяй и властвуй» и MapReduce. В этой части также обсуждаются декларативная компоновка, высокоуровневые абстракции в асинхронных операциях, агентное программирование и семантика передачи сообщений.
- В главе 4 изложены основы параллельной обработки большого количества данных, включая такие шаблоны, как Fork/Join.
- В главе 5 представлены более сложные методы параллельной обработки больших объемов информации, такие как параллельное агрегирование, сокращение данных и реализация параллельного шаблона MapReduce.
- В главе 6 представлена подробная информация о функциональных методах обработки потоков событий (данных) в реальном времени с применением функциональных операторов высокого порядка в .NET Reactive Extensions для формирования асинхронных комбинаторов событий. Изученные методы затем будут использованы для реализации рассчитанного на конкурентность реактивного шаблона «издатель — подписчик».
- В главе 7 дается объяснение модели программирования на основе задач в применении к функциональному программированию для реализации конкурентных операций с использованием шаблона Monadic. Затем этот метод применяется для построения конкурентного конвейера на основе функциональной парадигмы программирования.
- Глава 8 посвящена реализации неограниченных параллельных вычислений с помощью модели асинхронного программирования на C#. В этой главе также рассматриваются методы обработки ошибок и методы построения асинхронных операций.
- В главе 9 описывается асинхронный рабочий процесс на F#. В ней показано, как отсроченная и явная оценка в этой модели позволяет получить более высокую композиционную семантику. Затем мы научимся реализовывать пользовательские вычислительные выражения для повышения уровня абстракции до декларативного программирования.
- В главе 10 показано, как на основе знаний, полученных в предыдущих главах, можно реализовать комбинаторы и шаблоны, такие как Functor, Monad и Applicative, для составления и запуска нескольких асинхронных операций и обработки ошибок без побочных эффектов.
- В главе 11 анализируется реактивное программирование с использованием программной модели передачи сообщений. В ней раскрывается концепция естественной изоляции как технологии, дополняющей неизменяемость и позволяющей создавать конкурентные программы. В этой главе основное внимание уделяется классу MailboxProcessor, используемому в F# для распределения параллельной работы с применением агентного программирования и подхода без разделения ресурсов.
- В главе 12 описывается агентное программирование с использованием библиотеки TPL Dataflow из .NET с примерами на C#. Здесь показано, как реализовать на C# агенты без сохранения состояния и с сохранением состояния, а также как параллельно выполнить несколько вычислений, которые обмениваются данными между собой, применяя (передавая) сообщения в стиле конвейера.
В части III показано, как реализовать на практике все функциональные методы конкурентного программирования, изученные в предыдущих главах.
- В главе 13 представлен набор полезных рецептов для решения сложных проблем конкурентности, взятых из реальной практики. В этих рецептах используются все функциональные шаблоны, описанные в данной книге.
- В главе 14 описано полноценное приложение, разработанное и внедренное с применением функциональных конкурентных шаблонов и методов, изученных в этой книге. Вы создадите хорошо масштабируемое, отзывчивое серверное приложение и реактивную клиентскую программу. В книге представлены две версии: одна для iOS (iPad), созданная с помощью Xamarin Visual Studio, и вторая — созданная с помощью Windows Presentation Foundation (WPF). Для обеспечения максимальной масштабируемости в серверном приложении использована комбинация различных моделей программирования, таких как асинхронная, агентская и реактивная.
В книге также содержится три приложения.
- В приложении А кратко описаны основные понятия функционального программирования, а также представлена базовая теория функциональных методов, использованных в данной книге.
- В приложении Б раскрываются основные понятия языка F#. Это базовый обзор F#, который позволит вам ближе познакомиться с данным языком и комфортно чувствовать себя в процессе чтения книги.
- В приложении В наглядно демонстрируется несколько методов, упрощающих взаимодействие между асинхронным рабочим процессом на F# и задачей .NET на C#.
Отрывок. 11.6. F# MailboxProcessor: 10 000 агентов для Game of Life
По сравнению с потоками MailboxProcessor в сочетании с асинхронными рабочими процессами представляет собой простой вычислительный блок (примитив). Агенты могут появляться и уничтожаться с минимальными издержками. Можно распределить работу между несколькими объектами MailboxProcessor аналогично тому, как можно использовать потоки, без дополнительных накладных расходов, связанных с созданием нового потока. Благодаря этому вполне возможно создавать приложения, состоящие из сотен тысяч агентов, работающих параллельно, с минимальной нагрузкой на ресурсы компьютера.
В данном разделе мы воспользуемся несколькими экземплярами MailboxProcessor, чтобы реализовать игру Game of Life (игра «Жизнь») (wiki-англ и wiki-рус»). Согласно «Википедии», Game of Life, говоря простыми словами, является клеточным автоматом. Это игра без игроков — другими словами, когда игра начинается со случайной начальной конфигурации, она выполняется без каких-либо других входных данных. Игра состоит из набора клеток, образующих сетку; в каждой клетке выполняется несколько математических правил. Клетки могут жить, умирать и размножаться. Каждая клетка взаимодействует с восемью соседями (соседними клетками). Для перемещения клеток в соответствии с этими правилами необходимо постоянно вычислять новое состояние сетки.
Game of Life имеет следующие правила:
- если у клетки только один сосед или нет соседей, то она умирает «от одиночества»;
- если четверо или более соседей клетки умерло, то она умирает «из-за перенаселения»;
- если у клетки два или три соседа, то она остается жить;
- если у клетки три соседа, то она размножается.
В зависимости от начальных условий клетки образуют характерные структуры на протяжении всей игры. Посредством многократного применения правил создаются следующие поколения клеток, пока клетки не достигнут стабильного состояния (рис. 11.12).
В листинге 11.9 представлена реализация клетки Game of Life AgentCell, основанная на основе F#-типов MailboxProcessor. Каждая клетка-агент взаимодействует с соседними клетками посредством асинхронной передачи сообщений, создавая, таким образом, полностью распараллеленную Game of Life. Для краткости я опустил некоторые части кода, поскольку они не имеют отношения к основной теме примера. Полную реализацию вы найдете в исходном коде к этой книге, выложенном на сайте издательства.
AgentCell описывает клетку в сетке Game of Life. Основная концепция заключается в том, что каждый агент обменивается информацией с соседними ячейками о своем текущем состоянии посредством асинхронной передачи сообщений. Этот шаблон создает цепочку взаимосвязанных параллельных коммуникаций, которая задействует все клетки, отправляющие свое обновленное состояние агенту MailboxProcessor updateAgent. Получив эти данные, updateAgent обновляет графику в пользовательском интерфейсе (листинг 11.10).
updateAgent, как следует из названия, обновляет состояние каждого пиксела в соответствии со значением клетки, полученным в сообщении Update. Агент поддерживает состояние пикселов и задействует его для создания нового изображения, когда все клетки передадут свое новое состояние. Затем updateAgent обновляет графический пользовательский WPF-интерфейс, применяя это новое изображение, которое соответствует текущей сетке Game of Life:
do! Async.SwitchToContext ctx
image.Source <- createImage pixels
do! Async.SwitchToThreadPool()
Важно отметить, что агент updateAgent задействует текущий контекст синхронизации для корректного обновления WPF-контроллера. Текущий поток переключается на поток пользовательского интерфейса с помощью функции Async.SwitchToContext (описана в главе 9).
Последний фрагмент кода для выполнения Game of Life генерирует сетку, которая служит игровой площадкой для клеток, а затем таймер уведомляет клетки о необходимости выполнить обновление (листинг 11.11). В этом примере сетка представляет собой квадрат 100 × 100 клеток, всего 10 000 клеток (объектов MailboxProcessor), которые вычисляются параллельно по таймеру каждые 50 мс, как показано на рис. 11.13. Десять тысяч объектов MailboxProcessor взаимодействуют и обновляют пользовательский интерфейс 20 раз в секунду (код, на который следует обратить внимание, выделен жирным шрифтом).
Уведомления всем клеткам (агентам) рассылаются параллельно, с использованием PLINQ. Клетки представляют собой F#-последовательности, которые рассматриваются как .NET IEnumerable, что позволяет легко интегрировать LINQ/PLINQ.
При выполнении кода программа генерирует 10 000 F#-объектов типа MailboxProcessor менее чем за 1 мс, при этом агенты занимают в памяти менее 25 Мбайт. Впечатляет!
Резюме
- Агентная модель программирования естественным образом обеспечивает неизменяемость и изоляцию при написании конкурентных систем, благодаря чему становится проще обсуждать даже сложные системы, поскольку агенты инкапсулированы внутри активных объектов.
- Реактивный манифест определяет свойства для реализации реактивной системы, которая является гибкой, слабосвязанной и масштабируемой.
- Естественная изоляция важна для написания конкурентного кода без блокировок. В многопоточной программе изоляция решает проблему разделяемых состояний, предоставляя каждому потоку скопированную часть данных для выполнения локальных вычислений. При использовании изоляции отсутствует состояние гонки.
- Будучи асинхронными, агенты являются простыми, поскольку не блокируют потоки, ожидая сообщений. В результате можно задействовать сотни тысяч агентов в одном приложении без особого влияния на объем памяти.
- F#-объект MailboxProcessor предусматривает двустороннюю коммуникацию: агент может использовать асинхронный канал, чтобы возвратить (ответить) вызывающему объекту результат вычислений.
- Модель агентного программирования в F# посредством MailboxProcessor является отличным инструментом для решения проблем узких мест в приложениях, таких как множественный конкурентный доступ к базе данных. Фактически с помощью агентов можно значительно ускорить работу приложений, сохраняя отзывчивость сервера.
- Другие языки программирования .NET позволяют использовать F#-тип MailboxProcessor, предоставляя методы с применением удобной TPL-модели программирования на основе задач.
» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок
Для Хаброжителей скидка 20% по купону — Concurrency in .NET
По факту оплаты бумажной версии книги на e-mail высылается электронная версия книги.