Полное руководство параллельного программирования на Python

Куан Нгуен

 

Первая публикация на английском языке: Ноябрь 2018

Ссылка на продукт: 1231118

Все права защищены. Никакая часть этой книги не может быть воспроизведена, сохранена в поисковой системе или передана в любой форме или любыми средствами без предварительного письменного разрешения издателя, за исключением случаев кратких цитат, встроенных в критические статьи и обзоры.

При подготовке этой книги были предприняты все усилия чтобы гарантировать точность представленной информации. Тем не менее, информация, содержащаяся в этой книге, продаётся без гарантии в явном или неявном виде. Ни авторы, ни Packt Publishing, ни их дилеры и дистрибьюторы не будут нести ответственность за любые убытки, вызванные или предположительно вызванные прямо или косвенно этой книгой.

Packt Publishing пыталась предоставить информацию о товарных знаках обо всех компаниях и продуктов, упомянутых в данной книге для надлежащего использования капиталов. Тем не менее, Packt Publishing не может гарантировать точность этой информации.

Опубликовано Packt Publishing Ltd.

Livery Place

35 Livery Street

Birmingham B3 2PB, UK

ISBN 978-1-78934-305-2

www.packtpub.com

2018-12-10

 Состав исполнителей

Издания на английском языке
Автор
Куан Нгуен
Редактор выпуска
Рича Трайпати
Редактор разработки содержания
Зиян Пинхейро
Технический редактор
Роуми Диас
Литературный редактор
Safis Editing
Координатор проекта
Вайдихи Савант
Корректор
Safis Editing
Составитель указателя
Рикха Наир
Графика
Алишон Мендонса
Координатор производства
Апарна Бхагат

 Об авторе

Куан Нгуен является энтузиастом Python и учёным в области данных. В настоящее время он является инженером по анализу данных в Micron Technology, Inc. Обладая основательными знаниями в математике и статистике, Куан интересуется областями научных вычислений и обучения машин. При том что анализ данных находится в центре его внимания, Куан также также получает удовольствие от вовлечения технологий автоматизации в повседневные задачи с помощью программирования.

Страсть Куана к программированию привела его к активному участию в сообществе Python. Он начинал как основной автор книги Python for Scientists and Engineers и различных проектов с открытым исходным кодом в GitHub. Куан также является автором в Фонде программного обеспечения Python, а также время от времени вносит вклад в DataScience.com (часть Oracle).

 Рецензенты

Роман Пикар

Йогендра Шарма

Саймон Марцола

 www.PacktPub.com

 Содержание

Предисловие
Для кого эта книга
Что охватывает эта книга
Как получить максимальную отдачу от этой книги
Загрузка примеров кода этой книги
Загрузка цветных изображений этой книги
Принятые соглашения
Будьте на связи
Отзывы
Опечатки
Незаконное тиражирование
Вопросы
Глава 1. Расширенное введение в совместное и параллельное программирование
Технические требования
Что такое параллельность?
Сопоставление параллельной и последовательной обработок
Пример 1 - проверка является ли неотрицательное число простым
Сопоставление совместной и параллельной обработок
Быстрая метафора
Не всё может обрабатываться совместно
Ошеломительная одновременность
Внутренне присущая последовательность
Пример 2 - последовательные по своей сути задачи
Ограничения ввода/ вывода
История, настоящее и будущее совместной обработки
История совместной обработки
Настоящее
Будущее
Краткий обзор освоения одновременности в Python
Почему Python?
Настройка вашей среды Python
Общая установка
Выгрузка кода примеров
Выводы
Вопросы
Дальнейшее чтение
Глава 2. Закон Амдала
Технические требования
Закон Амдала
Терминология
Формула и интерпретация
Формула для закона Амдала
Пример по- быстрому
Следствия
Отношение закона Амдала к закону убывающей отдачи
Как выполнять эмуляцию в Python
Практические приложения закона Амдала
Выводы
Вопросы
Дальнейшее чтение
Глава 3. Работа с потоками в Python
Технические требования
Понятие потока
Сопоставление потоков и процессов
Многопоточность
Некий пример на Python
Обзор имеющегося модуля потоков
Модуль thread в Python 2
Модуль threading в Python 3
Создание нового потока в Python
Запуск потока при помощи thread
Запуск потока с применением threading
Синхронизация потоков
Понятие синхронизации потоков
Класс threading.Lock
Некий пример на Python
Многопоточная очередь с приоритетами
Взаимосвязь реального мира и программируемых очередей
Модуль queue
Постановка в очереди в параллельном программировании
Многопоточная очередь с приоритетами
Выводы
Вопросы
Дальнейшее чтение
Глава 4. Применение оператора with в потоках
Технические требования
Управление контекстом
Начинаем с управляющих файлов
Оператор with в качестве диспетчера контекста
Синтаксис оператора with
Оператор with при параллельном программировании
Пример обработки взаимной блокировки
Выводы
Вопросы
Дальнейшее чтение
Глава 5. Одновременные веб запросы
Технические требования
Основные понятия веб запросов
HTML
Запросы HTTP
Код состояния HTTP
Модуль requests
Создание запроса в Python
Запуск теста ping
Одновременные веб запросы
Порождение множества потоков
Перестройка логики запроса
Проблема таймаута
Поддержка со стороны httpstat.us и имитация на Python
Определение таймаута
Достойная практика создания веб запросов
Рассмотрение постулируемых условий служб и политик сбора данных
Обработка ошибок
Постоянное обновление вашей программы
Избегайте выполнять большое число запросов
Выводы
Вопросы
Дальнейшее чтение
Глава 6. Работа с процессами в Python
Технические требования
Понятие процесса
Сопоставление процессов и потоков
Множественность процессов
Вводный пример на Python
Обзор модуля multiprocessing
Класс process
Класс Pool
Определение значения текущего процесса, ожидание и завершение процессов
Определение значения текущего процесса
Ожидание процесса
Прекращение процесса
Взаимодействие между процессами
Передача сообщения для отдельного исполнителя
Обмен сообщениями межу несколькими исполнителями
Выводы
Вопросы
Дальнейшее чтение
Глава 7. Понижающие операторы в процессах
Технические требования
Концепция понижающих операторов
Свойства понижающих операторов
Примеры и то что ими не является
Пример реализации в Python
Приложения из реальной практики параллельных понижающих операторов
Выводы
Вопросы
Дальнейшее чтение
Глава 8. Параллельная обработка изображений
Технические требования
Основы обработки изображений
Python в качестве инструмента обработки изображения
Установка OpenCV и NumPy
Основы вычисления образа
Значения RGB
Пиксели и файлы изображения
Координаты внутри изображения
API OpenCV
Технологии обработки изображения
Формирование полутонового изображения
Установление пороговых значений
Применение параллельности для обработки изображений
Практические приёмы параллельной обработки изображений
Выбор верного способа (из множества)
Порождение подходящего числа процессов
Одновременная обработка ввода/ вывода
Выводы
Вопросы
Дальнейшее чтение
Глава 9. Введение в асинхронное программирование
Технические требования
Аналогия на скорую руку
Сопоставление асинхронности с прочими моделями программирования
Сопоставление асинхронного и синхронного программирования
Сопоставление асинхронного программирования с потоками и множеством процессов
Пример на Python
Выводы
Вопросы
Дальнейшее чтение
Глава 10. Реализация асинхронного программирования в Python
Технические требования
Модуль asyncio
Сопрограммы, цикл событий и фьючерсы
API Asyncio
Инфраструктура asyncio в действии
Асинхронный обратный отсчёт
Замечание относительно функций с блокировкой
Асинхронная проверка на простое число
Улучшения в Python 3.7
Задачи с внутренне присущим блокированием
concurrent.futures как некое решение для задач с блокировкой
Изменения в инфраструктуре
Примеры в Python
Выводы
Вопросы
Дальнейшее чтение
Глава 11. Построение каналов взаимодействия при помощи asyncio
Технические требования
Экосистема каналов взаимодействия
Уровни протокола взаимодействия
Асинхронное программирование каналов взаимодействия
Транспорт и протоколы в asyncio
Клиент сервера asyncio крупными мазками
Пример Python
Запуск сервера
Установка Telnet
Имитация канала соединения
Отправка сообщений обратно клиентам
Закрытие используемого транспорта
Взаимодействие стороны клиента с aiohttp
Установка aiohttp и aiofiles
Выборка кода HTML с вебсайта
Асинхронная запись файлов
Выводы
Вопросы
Дальнейшее чтение
Глава 12. Взаимные блокировки
Технические требования
Концепция взаимной блокировки
Задача обедающих философов
Взаимные блокировки в системах с параллельной обработкой
Эмуляция Python
Подходы к ситуациям с взаимными блокировками
Реализация ранжирования между ресурсами
Игнорирования блокировки и совместного использования ресурсов
Дополнительное замечание касательно блокировок
Заключительное соображение по поводу решения взаимных блокировок
Концепция динамического взаимного блокирования
Выводы
Вопросы
Дальнейшее чтение
Глава 13. Зависание
Технические требования
Понятие зависания
Что такое зависание?
Составление расписания
Ситуации зависания
Взаимосвязь зависаний с взаимной блокировкой
Проблема читатели- писатели
Постановка задачи
Первая проблема читатели- писатели
Вторая проблема читатели- писатели
Третья проблема читатели- писатели
Решения зависаний
Выводы
Вопросы
Дальнейшее чтение
Глава 14. Условия состязательности
Технические требования
Концепция состояния состязательности
Критичные разделы
Как появляется состязательность
Имитация состояния состязательности в Python
Блокирование в качестве решения состояния состязательности
Эффективное блокирование
Реализация в Python
Обратная сторона блокирования
Превращение параллельной программы в последовательную
Блокировки ничего не блокируют
Состояние состязательности в реальной жизни
Безопасность
Операционные системы
Сетевые среды
Выводы
Вопросы
Дальнейшее чтение
Глава 15. Глобальная блокировка интерпретатора
Технические требования
Введение в глобальную блокировку интерпретатора
Анализ управления памятью в Python
Проблемы, решаемые GIL
Проблемы, которые возбуждает GIL
Потенциальное удаление GIL из Python
Как работать с GIL
Реализация множественности процессов вместо многопоточности
Обход GIL при помощи естественных решений
Применение иного интерпретатора Python
Выводы
Вопросы
Дальнейшее чтение
Глава 16. Разработка параллельных структур данных, основанных на блокировании и отсутствии взаимных исключений
Технические требования
Параллельные структуры данных в Python на основе блокировок
LocklessCounter и состояние состязательности
Встраивание блокировок в структуру данных счётчика
Понятие масштабируемости
Анализ размеров масштабируемости определённой структуры данных счётчика
Аппроксимация счётчиков как некое решение масштабируемости
Основная мысль стоящая за аппроксимацией счётчиков
Реализация аппроксимирующих счётчиков в Python
Ряд соображений относительно проектирования аппроксимации счётчиков
Свободные от взаимного исключения параллельные структуры данных в Python
Невозможность избавиться от блокировок в Python
Введение в основные сетевые структуры данных
Реализация образца сетевой структуры данных в Python и состояние состязательности
RCU в качестве некого решения
Построение простых структур данных
Выводы
Вопросы
Дальнейшее чтение
Глава 17. Модели памяти и операции атомарных типов
Технические требования
Модель памяти Python
Основные компоненты диспетчера памяти Python
Модель памяти в виде помеченного ориентированного графа
В контексте параллельности
Атомарные операции в Python
Что такое быть атомарным?
Повторное рассмотрение GIL
Врождённая атомарность в Python
Сопоставление атомарность и не атомарности
Имитация в Python
Выводы
Вопросы
Дальнейшее чтение
Глава 18. Построение сервера с нуля
Технические требования
Сетевое программирование на нижнем уровне при помощи модуля socket
Теория взаимодействия стороны сервера
API модуля socket
Построение образца сервера echo
Построение сервера калькулятора при помощи модуля socket
Лежащая в основе логика вычислений
Реализация сервера калькулятора
Построение неблокируемого сервера
Анализ масштаба одновременных операций сервера
Генераторы в Python
Асинхронные генераторы и метод send
Изготовление сервера без блокирования
Выводы
Вопросы
Дальнейшее чтение
Глава 19. Тестирование, отладка и планирование параллельных приложений
Технические требования
Планирование с помощью APScheduler
Установка APScheduler
Неспланированная служба
Функциональность APScheduler
API APScheduler
Классы планировщика
Классы исполнителя
Ключевые слова триггера
Общие методы планирования
Примеры на Python
Планировщик с блокировкой
Планировщик фонового режима
Пул исполнителя
Запуск в облаке
Тестирование и параллельность в Python
Тестирование программ с параллельной обработкой
Тестирование элемента
Анализ статического кода
Параллельное тестирование программ
Отладка программ с параллельным кодом
Инструменты и техники отладки
Отладка и совместная обработка
Выводы
Вопросы
Дальнейшее чтение
Аттестация
Глава 1
Глава 2
Глава 3
Глава 4
Глава 5
Глава 6
Глава 7
Глава 8
Глава 9
Глава 10
Глава 11
Глава 12
Глава 13
Глава 14
Глава 15
Глава 16
Глава 17
Глава 18
Глава 19
Указатель

 Предисловие

Общеизвестно, что получить распараллеливание сложно, но, к счастью, язык программирования Python делает работу с одновременным исполнением удобной и простой. Эта книга показывает, как Python может применяться для программирования высокопроизводительных, надёжных, параллельных программ при помощи его уникальной формы программирования.

Данная книга предназначена для всех любознательных разработчиков, который заинтересован в создании быстрых и ресурсоёмких системных приложений без блокирования, причём в этой книге будут представлены наилучшие практические приёмы и шаблоны чтобы помочь вам внедрять параллельную обработку в ваши системы. Кроме того, будут обсуждаться новые темы параллельного программирования в Python, включая новый синтаксис AsyncIO, широко распространённое представление о том что "блокировки ничего не блокируют", использование атомарных очередей сообщений, архитектуры параллельных приложений и наилучших практических приёмов.

Мы будем разбираться со сложными концепциями и моделями параллельной обработки применяя практичные и интересные образцы кода. Прочитав эту книгу вы получите глубокое понимание основных компонентов из экосистемы параллельной обработки Python, а также практическое понимание различных подходов к задачам одновременной обработки из реальной жизни.

 Для кого эта книга

Если вы разработчик, знакомый с Python и вы желаете изучить как создавать высокопроизводительные приложения, которые масштабируются за счёт применения одноядерной, многоядерной или распределённой параллельной обработки, тогда эта книга для вас.

 Что охватывает эта книга

Глава 1. Расширенное введение в одновременность и параллельное программирование представляет для вас введение в понятие параллельной обработки и демонстрирует некого представителя, в котором параллельное программирование может существенным образом улучшить значение скорости программы Python.

Глава 2. Закон Амдала применяет теоретический подход и обсуждает имеющиеся ограничения параллельной обработки в деле улучшения значений скорости приложений. Мы рассмотрим что в действительности обеспечивает параллельная обработка и как мы можем применять её наилучшим образом.

Глава 3. Работа с потоками в Python вводит формальное определение потоков и обсуждает различные подходы к реализации потоков в программе на Python. В этой главе мы также обсудим основной элемент в параллелном программировании - понятие синхронизации.

Глава 4. Применение оператора with в потоках соединяет понятие управления контекстом с потоком в общем контексте параллельного программирования на Python. Мы введём саму основную идею, располагающуюся за управлением контекстом и то как он применяется в различных подходах к программированию, в том числе при использовании потоков.

Глава 5. Одновременные веб запросы охватывает одно из самых основных приложений в параллельном программировании: вытаскивание данных из веб (веб скрапинг). Помимо этого она также обсуждает сами понятия вытаскивания данных из веб, наряду с прочими относящимися к этому элементами, прежде чем обсуждать как могут применяться потоки для программ по вытаскиванию веб данных для достижения значительного ускорения.

Глава 6. Работа с процессами в Python показывает формальное определение многопроцессности и то, как его поддерживает Python. Мы также дополнительно изучим основные ключевые различия между потоками и множеством процессов, которые зачастую путаются один с другим.

Глава 7. Снижение числа операций в процессах впрягает в пару понятие снижение числа операций и многопроцессность воедино как некий практический приём параллельного программирования. Эта глава пройдёт по теоретической основе снижения операций и того как это соотносится с множеством процессов при программировании в целом.

Глава 8. Параллельная обработка изображений перейдёт к практическому приложению параллельных вычислений: обработке изображений. Обсуждаются основные идеи, стоящие за обработкой изображений в добавление к некоторым из наиболее распространённых технологий обработки. Конечно, мы покажем как одновременность, в частности для множества процессов, может ускорить задачу обработки изображения.

Глава 9. Введение в асинхронное программирование рассматривает формальное понятие асинхронного программирования как одну из трёх основных моделей параллельного программирования помимо потоков и множества процессов. Мы изучим чем асинхронное программирование фундаментальным образом отличается от двух иных упоминаний, но всё ешё ускоряет параллельные приложения.

Глава 10. Реализация асинхронного программирования в Python углубляется в тот API, который Python предоставляет для обслуживания асинхронного программирования. В частности, мы изучим модуль asyncio, который является основным инструментом для реализации асинхронного программирования в Python, а также общую структуру некоего асинхронного приложения.

Глава 11. Построение каналов взаимодействия при помощи asyncio соединяет основные знания, относящиеся к асинхронному программированию, обсуждавшемуся в предыдущих главах, с основной темой сетевого взаимодействия. В частности, мы рассмотрим использование модуля aiohttp как некоего инструмента для изготовления асинхронных запросов HTTP к веб серверам, а также модуля aiofile, который реализует асинхронные чтение/ запись в файлы.

Глава 12. Взаимные блокировки представляет введение в самую первую из тех проблем, с которыми обычно сталкиваются при параллельном программировании. Мы изучим классическую задачу обедающих философов в качестве того как взаимные блокировки могут останавливать функционирование параллельных программ. Эта глава также охватывает некоторое число потенциальных подходов к взаимным блокировкам, а также относящиеся к ним понятия, такие как динамическое взаимное блокирование и распределённые взаимные блокировки.

Глава 13. Зависание рассматривает другую распространённую проблему в параллельных приложениях. Эта глава использует изложение классической задачи читатели- писатели для пояснения самого понятия зависаний и их причин. Конечно, мы также обсудим потенциальные решения этих проблем посредством практичных примеров Python.

Глава 14. Условия состязательности адресована основательно считающейся наиболее известной проблеме параллельной обработки: состоянию состязательности. Также мы обсудим основное понятие критического раздела, который является неким существенным элементом в самом контексте состояния состязательности в частности, а также параллельного программирования в целом. Данная глава затем рассмотрит взаимные исключения как некое потенциальное решение данной проблемы.

Глава 15. Глобальная блокировка интерпретатора представляет введение в имеющий дурную репутацию GIL, который рассматривается как самый большой вызов параллельного программирования в Python. Мы изучим основную причину стоящую за реализацией GIL, а так также те проблемы, которые она вызывает. Данная глава завершается некими рассуждениями относительно того что думают о GIL программисты и разработчики Python, а также как они с ним взаимодействуют.

Глава 16. Разработка параллельных структур данных, основанных на блокировании и отсутствии взаимных исключений анализирует собственно процесс двух общих структур параллельных данных, вовлекаемых в блокировки в качестве механизма синхронизации: основанных на блокировке и свободных от взаимных исключений. В данную главу включаются некоторые расширенные анализы имеющихся реализаций таких структур данных, а также их производительности с тем, чтобы читатели выработали критический настрой, когда дело доходит до разработки параллельных приложений.

Глава 17. Модели памяти и операции атомарных типов содержит теоретические темы, которые вовлечены в лежащие в основе языка Python структуры и то как программисты могут получать из этого преимущества в своих параллельных приложениях. Также для читателей в этой главе вводится концепция атомарных операций.

Глава 18. Построение сервера с нуля проводит читателей по процессу построения сервера без блокировок на нижнем уровне. Мы изучим функциональности сетевого программирования, предоставляемые в Python модулем socket, а также как мы можем применять его к реализации функционирующего сервера. Мы также те общие структуры асинхронного программирования, которые обсуждались ранее в этой книге для преобразования сервера с блокировками в неблокирующий сервер.

Глава 19. Тестирование, отладка и планирование параллельных приложений покрывает использование параллельных программ на верхнем уровне. Данная глава вначале рассмотрит как параллельная обработка может применяться к задачам планирования приложений Python посредством модуля APScheduler. Затем мы обсудим те сложности, которые проистекают из одновременности в темах проверок и отладки программ Python.

 Как получить максимальную отдачу от этой книги

Читатели этой книги должны знать как исполнять программы Python в некоторой среде разработки или просто из командной строки. Они также должны быть знакомы с общим синтаксисом и практическими приёмами программирования на Python (переменные, функции, импорт пакетов и тому подобное). В различных местах этой книги предполагается наличие неких базовых знаний вычислительной науки относительно таких элементов как пиксели, стек исполнения и инструкции в кодах байт.

Окончательный раздел Главы 1. Расширенное введение в одновременность и параллельное программирование обсуждает процесс настройки вашей среды исполнения. Главы из данной книги могут обсуждать применение внешних библиотек или инструментов, которые следует установить через некий диспетчер пакетов, например pip или Anaconda, а также особые инструкции относительно того как установить эти библиотеки, включаемые в относящиеся к ним главы.

 Загрузка примеров кода этой книги

Вы можете выгрузить все файлы примеров кода для данной книги из своей учётной записи www.packtpub.com. Если вы приобрели эту книгу в ином месте, будьте добры, пройдите в www.packtpub.com/support и зарегистрируйтесь чтобы иметь эти файлы высланные непосредственно вам по электронной почте.

Вы можете выгрузить все файлы кодов пройдя следующие шаги:

  1. Зайдите зарегистрированным пользователем на www.packtpub.com.

  2. Выберите закладку SUPPORT.

  3. Кликните по Code Downloads & Errata.

  4. Введите название нужной вам книги в блоке Search и следуйте появляющимся на экране инструкциям.

После того, как необходимые файлы выгружены, убедитесь что вы раззиповали или раскрыли их в нужную папку при помощи самой последней версии:

  • WinRAR/7-Zip для Windows.

  • Zipeg/iZip/UnRarX для Mac.

  • 7-Zip/PeaZip для Linux.

Пакет кода также размещён на GitHub по адресу https://github.com/PacktPublishing/Mastering-Concurrency-in-Python. Также у нас имеются и другие пакеты кода из нашего богатого каталога книг и видео, доступные по адресу https://github.com/PacktPublishing/. Следите за изменениями!

 Загрузка цветных изображений этой книги

Мы дополнительно снабжаем вас файлом PDF, который содержит цветные изображения экранных снимков/ схем, использованных в данной книге. Цветные изображения помогут вам лучше понять изменения в выводе. Вы можете загрузить этот файл по адресу: https://www.packtpub.com/sites/default/files/downloads/9781789343052_ColorImages.pdf.

 Код в действии

Чтобы проверить наличие видеоматериалов исполняемого кода посетите следующую ссылку: http:/​/​bit.​ly/​2BsvQj6.

 Соглашения

В данной книге вы найдёте ряд текстовых стилей, которые делают разницу между различными видами информации. Здесь мы приводим некоторые примеры этих стилей и объяснение их назначения.

CodeInText указывает кодовые слова в тексте, имена таблиц базы данных, имена папок, имена файлов, расширения файлов, имена путей, модели URL-адресов, ввод пользователя, и регулировки Twitter. Вот некий пример: "Данный модуль asyncio предоставляет некое число различных классов транспорта.".

Блок кода устанавливается следующим образом:


async def main(url):
    async with aiohttp.ClientSession() as session:
        await download_html(session, url)
 	   

Если вы желаете привлечь внимание к определённой части блока кода,соответствующие строки или элементы выделяются жирным:


apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: cli-hello-world
  labels:
    app: nginx
 	   

Когда вы выделить своё внимание к определённой части кодового блока, соответствующие строки или элементы выделяются жирным:


urls = [
    'http://packtpub.com',
    'http://python.org',
    'http://docs.python.org/3/library/asyncio',
    'http://aiohttp.readthedocs.io',
    'http://google.com'
]
 	   

Любой ввод командной строки или её вывод записываются следующим образом:


> python3 example5.py
Took 0.72 seconds.
 	   

Жирно: указывает новый термин, важное слово которые вы видите на экране, например, в меню или блоках диалогов появляются именно так. Вот пример: "Для выгрузки соответствующего репозитория просто кликните по кнопке Clone or download в правом верхнем углу своего окна.".

[Замечание]Замечание

Предостережения или важные замечания появляются в блоках подобных этому.

[Совет]Совет

Советы и ловкие приёмы возникают таким образом.

 Будьте на связи

Обращения наших читателей всегда приветствуются.

Обычная обратная связь: Пошлите электронное письмо на адрес feedback@packtpub.com с упоминанием заголовка книги в теме вашего сообщения. Если у вас имеются вопросы относительно любых сторон данной книги, обратитесь, пожалуйста, по адресу questions@packtpub.com.

Ошибки: Хотя мы и предприняли все меры чтобы гарантировать точность содержимого, ошибки могут иметь место. Если вы обнаружили ошибку в данной книге, мы будем вам признательны если вы сообщите нам о ней. Посетите, пожалуйста, www.packtpub.com/submit-errata, выбрав вашу книгу, кликнув на ссылку Errata Submission Form, и заполнив подробности найденной вами ошибки.

Пиратство: Если вы столкнётесь с какой-либо незаконной копией наших работ в любой форме в Интернете, пожалуйста, предоставьте нам сразу адрес местонахождения или имя веб-сайта, чтобы мы могли принять меры. Пожалуйста, обратитесь по адресу copyright@packtpub.com со ссылкой на материалы содержащие признаки нарушения авторских прав. {Прим. пер.: Согласно закону об авторском праве РФ, авторские права на перевод принадлежат авторам этого перевода. Данным переводом, по нашему мнению, мы служим популяризации основных стратегических направлений развития тем Packt. В случае наличия конструктивных предложений, готовы к тесному сотрудничеству.}.

Если вы желаете стать нашим автором: Если у вас существует тема, в которой у вас имеется опыт и вы заинтересованы либо в написании, либо во вкладе в книгу, обратитесь к руководству по адресу authors.packtpub.com.

 Отзывы

Оставляйте, пожалуйста, отзывы. Если вы прочли и воспользовались данной книгой, почему бы вам не оставить отзыв на том сайте, на котором вы её приобрели? Потенциальные читатели затем смогут увидеть и применить ваше беспристрастное суждение чтобы принять решение о приобретении, мы в Packt сможем понять что вы думаете о нашем продукте, а наши авторы увидят обратную связь относительно своей книги. Мы заранее благодарим вас!

Для получения дополнительной информации о Packt посетите, пожалуйста packtpub.com.