C Thread - это что такое? Набор для практики. Примеры реализаций смешанных потоков

Что общего у футболки и компьютерной программы? Они обе состоят из многих потоков! В то время как нитки в футболке держат ткань в виде единого полотна, C Thread (в буквальном смысле — «нити» или «потоки») операционной системы объединяют все программы, для того чтобы выполнить последовательные или параллельные действия одновременно. Каждый поток в программе идентифицирует процесс, который запускается, когда система (system Thread C) запрашивает его. Это оптимизирует работу такого сложного устройства как персональный компьютер и положительно сказывается на его быстродействии и производительности.

Определение

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

Для потоков обычно задается определенный приоритет, что означает, что некоторые потоки имеют приоритет над другими. Как только процессор завершит обработку одного потока, он может запустить следующий, ожидающий очереди. Как правило, ожидание не превышает нескольких миллисекунд. Компьютерные программы, реализующие «многопоточность», могут выполнять сразу несколько потоков. Большинство современных ОС поддерживают С Thread на системном уровне. Это означает, что когда одна программа пытается забрать все ресурсы процессора, система принудительно переключается на другие программы и заставляет программу поддержки процессора разделять ресурсы равномерно.

Термин «поток» (С Thread) также может ссылаться на серию связанных сообщений в онлайн-обсуждении. Веб-доски объявлений состоят из множества тем или веток. Ответы, отправленные в ответ на исходную публикацию, являются частью одного и того же потока. В электронной почте поток может ссылаться на серию ответов в виде команд «назад» и «вперед», относящихся к определенному сообщению, и структурировать дерево беседы.

Многопоточность C Thread в Windows

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

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

Примеры работы инструмента C Thread task

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

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

Многозадачность

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

Историческая ретроспектива

Ранние операционные системы могли запускать сразу несколько программ, но не полностью поддерживали многозадачность. Одна программа могла потреблять все ресурсы процессора при выполнении определенной операции. Основные задачи операционной системы, такие как копирование файлов, не позволяли пользователю выполнять другие задачи (открытие или закрытие окон, например).

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

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

Одиночные и многопроцессорные системы

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

Системы с одним процессором реализуют многопоточность по времени: центральный процессор (CPU) переключается между различными потоками программного обеспечения. В многопроцессорной, а также в многоядерной системе, некоторое количество потоков выполняется в параллельном режиме, причем каждый процессор или ядро ​​выполняют отдельный поток одновременно.

Виды потоков

Планировщики процессов большинства современных ОС напрямую поддерживают как временную, так и многопроцессорную потоковую обработку, в то время как ядро ​​операционной системы позволяет разработчикам управлять потоками, предоставляя нужные функции через интерфейс системного вызова. Некоторые потоковые реализации называются потоками ядра, тогда как легкие процессы (LWP) — это тип потока, который имеет одно и то же информационное состояние. Также программные решения могут иметь потоки пространства пользователя, когда они используются с таймерами (Thread timer C), сигналами или другими методами, чтобы прервать их собственное выполнение, выполняя своего рода временную привязку ad hoc.

Потоки и процессы: отличия

Потоки отличаются от классических процессов многозадачной ОС следующими характеристиками:

    процессы обычно независимы, тогда как потоки существуют как подмножества процесса;

    процессы несут гораздо больше информации, чем потоки;

    процессы имеют выделенные адресные пространства;

    процессы взаимодействуют только через системные механизмы коммуникации;

    переключение контекста между потоками в процессе происходит оперативнее, чем переключение контекста между процессами.

Превентивное и совместное планирование

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

Эволюция технологии

До начала 2000-х гг. на большинстве настольных компьютеров был только один одноядерный процессор, который не поддерживал аппаратные потоки. В 2002 г. компания Intel реализовала поддержку одновременной многопоточности на процессоре Pentium 4, который носит имя Hyper-Threading. В 2005 г. был представлен двухъядерный процессор и двухъядерный процессор AMD Athlon 64 X2.

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

Модели

Перечислим основные модели реализации.

1: 1 (поток на уровне ядра) — темы, созданные пользователем в ядре, являются простейшей возможной реализацией потоков. OS/2 и Win32 используют этот подход изначально, тогда как в Linux Thread join реализует данный подход через NPTL или более старые LinuxThreads. Этот подход также используется Solaris, NetBSD, FreeBSD, macOS и iOS.

N: 1 (пользовательский поток) — эта модель предусматривает, что все потоки уровня приложения сопоставляются с одним запланированным объектом уровня ядра. При таком подходе контекстное переключение может быть выполнено очень быстро, и, кроме того, его можно даже реализовать на тех ядрах, которые не поддерживают потоковую обработку. Однако один из основных недостатков заключается в том, что он не выигрывает от аппаратного ускорения на многопоточных процессорах или компьютерах. Например: если один из потоков необходимо выполнить при запросе ввода-вывода, весь процесс блокируется и потоковая передача не может быть использована. В GNU Portable C Thread exception используется как потоковая обработка пользовательского уровня.

M: N (гибридная реализация) — модель отображает некоторое количество потоков приложений для некоторого N числа ячеек ядра, или «виртуальных процессоров». Это компромисс между потоками уровня ядра («1: 1») и пользователя («N: 1»). Системы потоковой передачи «M: N» более сложны, поскольку требуются изменения как кода ядра, так и кода пользователя. В реализации M: N библиотека потоковой обработки отвечает за планирование потоков в доступных планируемых сущностях. Это делает контекст самым оптимальным, поскольку позволяет избежать вызовов системы. Однако это увеличивает сложность и вероятность инверсии, а также субоптимальное планирование без обширной (и дорогостоящей) координации между планировщиком пользовательской среды и планировщиком ядра.

Примеры гибридной реализации — активация планировщика, используемая встроенной реализацией библиотеки POSIX NetBSD (для модели M: N, в отличие от модели реализации ядра 1: 1, или модели пользовательского пространства).

Легкие процессы, используемые более старыми версиями операционной системы Solaris (инструментарий Std Thread C).

Поддержка языков программирования

Многие формальные системы поддерживают функциональность потоков. Реализации C и C++ реализуют эту технологию и обеспечивают доступ к собственным API-интерфейсам для операционной системы. Некоторые языки программирования более высокого уровня, такие как языки Java, Python и.NET Framework, выставляют потоки разработчикам при абстрагировании специфических различий в реализации потоков в среде выполнения. Другие языковые расширения также пытаются абстрагировать концепцию параллелизма и потоковой передачи от разработчика. Некоторые языки предназначены для последовательного параллелизма с использованием графических процессоров.

Ряд интерпретируемых языков имеет реализации, которые поддерживают потоковую и параллельную обработку, но не параллельное выполнение потоков из-за глобальной блокировки интерпретатора (GIL). GIL — это блокировка взаимного исключения, выполняемая интерпретатором, которая может помешать одновременно интерпретировать код приложения на двух или более потоках одновременно, что ограничивает параллелизм в многоядерных системах.

Другие реализации программирования, такие как Tcl, используют расширение Thread sleep C. Это позволяет избегать максимального предела GIL, используя модель, где контент и код должны быть явным образом «разделены» между потоками.

Языки программирования приложений, ориентированные на события, такие как Verilog, и расширение Thread sleep C, имеют иную модель потоков, которая поддерживает максимальное их число для моделирования оборудования.

Практическая многопоточность

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

Хотя добросовестное и регулярное проведение сплит-тестов может дать до 10% увеличения конверсии, существуют другие стратегии, способные приносить более ощутимые результаты. В этой статье мы рассмотрим одну из них, основанную на «капитальном ремонте» офферов и структуры маркетинговых воронок с учетом (user flow), проходящего через сайт.

Вашему вниманию — кейс от Бреда Смита (Brad Smith), являющегося одним из партнеров-основателей агентства Codeless Interactive и завсегдатаем таких проектов, как Kissmetrics, WordStream, AdEspresso и др. Он описал реальные примеры и пошаговый процесс оптимизации пользовательского потока . По результатам внедренных им мероприятий был достигнут 166% прирост новых лидов в течение 3 месяцев (см. иллюстрацию и комментарий ниже):

Результаты оптимизации пользовательского потока за 3 месяца по сравнению с предыдущим периодом (на средней части картинки показано, что количество привлеченных новых лидов (Contacts) увеличилось с 574 до 1 528, что составляет 166.2% рост)

Почему сплит-тестирование не всегда приносит ощутимый результат?

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

Однако зачастую такая радужная ситуация характерна только для частных случаев. Общая же картина на практике выглядит несколько иначе.

1. Во-первых, «крошечные изменения» в подавляющем большинстве приводят к «крошечным результатам» (если таковые вообще имеются). Более того, полученные в ходе сплит-тестирования результаты показывают одну стойкую, но неутешительную тенденцию: со временем показатели конверсии «откатываются» к средним значениям (см. график и комментарий ниже). Такой вывод был сделан сервисом PPC-аналитики WordStream на основании анализа деятельности тысяч аккаунтов контекстной рекламы AdWords, годовой рекламный бюджет которых составил свыше $3 000 000 000.

Пример результатов А/Б-теста: на графике синим цветом показан всплеск роста конверсии в начале тестирования и постепенное снижение показателей до среднего уровня, которое произошло в течение определенного временного промежутка

2. Во-вторых, практика тестирования требует наличия определенного объема данных для анализа. Это нужно, чтобы выборка считалась репрезентативной (достоверной). Например, если ваша посадочная страница не генерирует за месяц хотя бы 1 000 подписчиков, то вы не можете тестировать ее элементы. Точнее говоря, конечно же, это возможно, но полученные результаты нельзя будет считать достоверными из-за недостаточного объема данных. Другой пример: вы проводите А/Б-тест, имея 500 конверсий в месяц; результаты теста дают показатель 250 на 250 по испытываемым вариантам. Очевидно, что такой исход событий не позволяет выявить победителя. Нужен больший объем выборки.

Другими словами, целый сегмент малых и средних онлайн-бизнесов не могут заниматься достоверным тестированием лишь потому, что пока не имеют достаточного объема конверсий.

Но и это еще не все…

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

Как уже отмечалось выше, в качестве альтернативы можно использовать CRO стратегию, позволяющую получить более чем 10%-ный прирост коэффициента конверсии, фокусируясь при этом не на мелочах, а на усовершенствовании всего пользовательского потока, или так называемой « ».

Как работает оптимизация пользовательского потока?

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

— слева (для сайта электронной коммерции): контекстная реклама → товарный лендинг или карточка товара в интернет-магазине → покупка товара;
— справа (для сайта с платной подпиской или посадочной страницы): входящий трафик из социальных сетей → посадочная страница → подписка на email-рассылку

Очевидно, что представленные выше различия должны определять не только дизайн сайта, но и особенности его функционала. Именно за разработку таких индивидуальных решений интернет-предприниматели платят большие деньги веб-студиям.

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

Squarespace предлагает красивые шаблоны, которые могут использоваться в различных рыночных нишах. Однако общий минус всех подобных конструкторов состоит в недостатке опций, позволяющих настроить работу сайта или landing page с учетом индивидуальных особенностей конкретного проекта

При этом зачастую упускается из виду (или умалчивается) один очень важный момент: насколько эффективно эти внешне красивые страницы могут взаимодействовать в рамках всего веб-ресурса.

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

При идеальном стечении обстоятельств такой пользовательский опыт может позволить отдельным посетителям найти то, за чем они пришли, и совершить покупку здесь и сейчас. Однако не стоит забывать, что по данным авторитетного маркетингового агентства Moz наиболее лояльными клиентами становятся те, кто посетил сайт порядка 10 раз, а не совершил конверсионное действие в первые 1-3 визита.

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

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

Но если вы начнете анализировать пользовательские потоки, то сможете неоднократно убедиться, что многие люди даже не заходят на главную страницу. Они либо переходят с объявления контекстной рекламы прямо на landing page, либо вводят в поисковую систему коммерческий запрос и направляются сразу на товарный лендинг или страницу с описанием запрашиваемой услуги.

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

Три примера пользовательских потоков, где в качестве отправных точек выступают разные источники:
— слева: ссылка с результатов выдачи поисковых систем → landing page → подписка на рассылку;
— в центре: прямая ссылка на сайт из закладок или введенная прямо в адресную строку браузера → главная страница → страница с описанием товара или услуги → добавление в корзину → оплата;
— справа: объявление контекстной рекламы → лендинг → покупка

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

Как анализировать пользовательский поток вашего сайта?

Итак, одним из наилучших способов повышения конверсии лендинга является приведение в соответствие рекламного объявления и оффера на посадочной странице. Это означает, что человек, вводящий запрос в поисковую систему, видит релевантное запросу контекстное объявление, и, кликая по нему, он попадает на landing page, контент которой полностью соответствует его содержанию. Таким образом посетитель получает именно то, что он запрашивал в поисковике.

Оптимизация пользовательского потока происходит приблизительно по такой же схеме за исключением того, что вы расширяете этот процесс, перенося его на весь путь потенциального клиента: начиная от источника трафика и заканчивая путешествием по сайту в «точку назначения». При этом нужно связывать каждую веб-страницу — или отдельное письмо серийной (follow-up) рассылки — с предыдущей.

Вот примерный алгоритм того, как это может выглядеть на практике.

Шаг #1. Определите, откуда приходят пользователи (чтобы понять, что они ищут)

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

Чтобы смоделировать путешествие потребителя применительно к определенному онлайн-бизнесу, можно использовать сервис Customer Journey to Online Purchase от компании Google, помогающий выяснить, какие маркетинговые каналы чаще всего используют пользователи в той или иной маркетинговой нише (см. иллюстрацию и комментарий ниже):

Пример интерфейса Customer Journey to Online Purchase, иллюстрирующего, какие каналы используют потребители небольших (опция «Small») сайтов электронной коммерции (опция «Shopping»), действующих с таргетингом на США (опция «The USA»)

Комментарий к иллюстрации . Перечисленные выше опции можно задавать применительно к разным сферам и географическим локациям веб-сайтов. Чем левее на графике канал, тем менее готовым к покупке будет приходящий из него посетитель. На приведенном примере таковыми являются пользователи, привлеченные из органической выдачи поисковиков (Organic Research). Наиболее горячая целевая аудитория в этой нише — те, кто переходят на сайт по прямой ссылке (Direct), вводя ее в адресную строку браузера или активируя ее из закладок. Поэтому канал Direct расположен крайним справа. Подобным же образом анализируются , показанные ближе к центру графика.

По словам разработчиков Customer Journey to Online Purchase, исходными данными для этого сервиса являются результаты анализа миллионов пользовательских взаимодействий, собираемых Google Analytics.

Поэтому логичным продолжением этого шага оптимизации пользовательских потоков на лендинге или сайте должно быть рассмотрение собранных в системе Google Analytics данных вашего проекта (см. колонку «Источники/Каналы» (Sources/Mediums)). Вот как это может выглядеть на реальном примере:

Несложно заметить, что большинство пользователей приходят на сайт из первых 3 источников: органическая выдача поисковой системы (в таблице — «google/organic»), переходы по прямым ссылкам (в таблице — «direct») и платный поисковый трафик (в таблице — «google/cpc»).

Если наложить информацию об источниках трафика на данные о популярных страницах — для этого в системе Google Analytics есть специальный отчет «Top Content»,— то можно визуализировать и проследить, как перемещаются по сайту посетители, впервые привлеченные на веб-ресурс:

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

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

1. Большинство посетителей уже осведомлены о компании, так как приходят на сайт по прямой ссылке или вводят в поисковую систему запросы, содержащие название бренда. Поэтому большая часть трафика направляется сразу на главную страницу, страницу «О нас» и на страницу с описанием товара/услуги. (В такой ситуации создание блога, например, может привлечь новых посетителей еще незнакомых с компанией).

2. Второй сегмент — это люди, привлекаемые с помощью платного поискового трафика. Они сразу направляются на landing page. С этой группой все ясно и понятно.

Шаг #2. Проанализируйте, какие элементы посещаемых страниц работают, а какие — нет

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

Эта работа предполагает построение так называемой системы микроконверсий — небольших взаимодействий и серий писем, которые получает человек, последовательно переходя от одной страницы или подписной формы (opt-in) к следующей (см. схему и комментарий ниже):

Схема, иллюстрирующая систему микроконверсий, которую должен пройти посетитель, прежде чем перейти на более высокий уровень лояльности: (1) главная страница → (2) переход на вложенную страницу через меню сайта → (3) реакция на полезный контент → (4) подписка на лендинге, «заточенном» под посетителей верхнего уровня воронки (TOFU) → (5) благодарственная страница с новым оффером (для перевода на средний уровень воронки (MOFU)) и email с полезным контентом → (6) переход и подписка на лендинге, «заточенном» под посетителей среднего уровня воронки (MOFU) → (7) благодарственная страница с новым оффером (для перевода на нижний уровень воронки (BOFU)) и email с полезным контентом → (8) лояльный подписчик и вход в продажу

Имея такую последовательную цепочку, можно довольно точно выявить «слабые звенья», тормозящие процесс перехода от одной микроконверсии к следующей, и внедрить корректирующие мероприятия по устранению проблемных, узких мест пользовательского потока.

Представленная выше схема может показаться слишком усложненной, однако практика показывает, что в подавляющем большинстве случаев необходимо 6-8 «касаний» с посетителем, чтобы добиться окончательной конверсии в покупку. Игнорирование этого принципа часто можно наблюдать, когда через настроенные в Facebook или ВКонтакте рекламные объявления холодный трафик направляется сразу на landing page с коммерческим оффером. Оптимизация пользовательского потока в таком случае предполагает внедрение так называемой системы взращивания клиентов (lead nurturing) — специально разработанной кампании (drip campaign) — включая последовательную серию писем,— направленной на повышение лояльности новых посетителей сайта.

Когда проблема выявлена, остальное — дело техники. Например, можно использовать доступный функционал в соцсетях, чтобы автоматически добавлять новые контакты для дальнейшего взаимодействия с ними через сервисы почтовой рассылки или Saas-платформы автоматизации маркетинга (MailChimp, Infusionsoft, HubSpot и др.):

На иллюстрации показано, как с помощью полезной CRM AdEspresso настраивается автоматическое добавление новых контактов из Facebook в HubSpot для последующей работы с лидами

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

Для такого анализа лучше всего использовать специализированные сервисы, которые позволяют генерировать наглядные визуальные изображения (тепловые карты), характеризующие поведение онлайн-пользователей на исследуемом объекте. Зачастую такие кейсы являются более информативными, с ними легче работать и проще доносить полученные результаты до клиентов и начальства. Далее в статье будут рассмотрены примеры такого анализа, полученные с использованием соответствующего функционала SaaS-платформы CrazyEgg.

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

Карта прокрутки позволяет оценить, насколько далеко посетитель опускается вниз страницы в ходе изучения контента, задействуя скроллинг. Проиллюстрированные выше результаты показывают, что никто не переходит так называемую «линию сгиба» (below the fold), а читает лишь то, что представлено на первом экране

Чтобы интерпретировать представленную на картинке информацию, нужно обратить внимание на цветовую шкалу, расположенную в правом нижнем углу: чем «горячее» цвет, тем больше внимания пользователей привлекает окрашенная в него часть страницы, а чем «холоднее» — тем меньше посетителей добрались до соответствующей части веб-страницы или лендинга (как до дна голубого океана, куда почти никто не погружается).

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

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

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

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

Шаг #3. Оптимизируйте дизайн и контент страниц с учетом особенностей пользовательского потока

Что возникает в вашем воображении, когда вы слышите слово «дизайнер» (designer)? Большинство скажут, что это человек, создающий внешний вид лендинга. Однако у английского слова «designer» есть еще несколько значений, два из которых — конструктор, проектировщик. Поэтому (в глубинном смысле) дизайн посадочной страницы — это не то, как она выглядит, а то, как она работает .

Такое понимание предполагает, что дизайн landing page должен разрабатываться с мыслью о том, какие конверсионные цели должны быть достигнуты с ее помощью. В качестве последних может выступать добавление в корзину (заказ или покупка), но чаще — заполнение лид-формы.

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

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

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

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

На иллюстрации изображена таблица распределения кликов среди всех кликабельных элементов страницы (СТА-кнопки, текстовые ссылки, картинки и др.). В подавляющем большинстве случаев (45%) посетители кликают именно на СТА-кнопку (Download Now) в лид-форме. Это является показательным признаком конверсионной страницы

Если подавляющее большинство кликов на вашей посадочной странице приходится на СТА-кнопку, значит вы на правильном пути. Но если чувствуете, что в этом вопросе вам есть что улучшить, адаптируйте к своему бизнесу — практический материал из рубрики нашего блога, содержащей проверенные принципы и примеры дизайна landing page с высокой конверсией.

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

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

  • если посетители относятся к категории TOFU (находятся в верхней части воронки и мало знакомы с брендом), то нужна форма с минимальным количеством полей для заполнения;
  • если же большая часть трафика представляют группу BOFU (находятся в нижней части воронки, уже получали полезный контент и лояльно относятся к бренду), то при необходимости можно использовать более подробную лид-форму.

Суровая реальность интернет-маркетинга такова, что не зная структуры пользовательского потока, бывает очень проблематично существенно повысить конверсию landing page. Поэтому нередко приходится переделывать уже готовый дизайн с учетом особенностей входящего трафика (см. иллюстрацию и комментарий ниже):

Модели многопоточности. Реализация многопоточности в ОС, как и многих других возможностей, имеет несколько уровней абстракции. Самый высокий из них – пользовательский уровень. С точки зрения пользователя и его программ, управление потоками реализовано через библиотеку потоков пользовательского уровня (user threads). Подробнее конкретные операции над пользовательскими потоками будут рассмотрены немного позже. Пока отметим лишь, что существует несколько моделей потоков пользовательского уровня, среди которых:

  • POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX-приложениях (рассмотрены позже в данной лекции);
  • Mac C-threads – пользовательские потоки в системе MacOS;
  • Solaris threads – пользовательские потоки в ОС Solaris (рассмотрены позже в данной лекции).

Низкоуровневые потоки, в которые отображаются пользовательские потоки, называются потоками ядра (kernel threads). Они поддержаны и используются на уровне ядра операционной системы. Как и подходы к пользовательским потокам, подходы к архитектуре и реализации системных потоков и к отображению пользовательских потоков в системные в разных ОС различны.Например, собственные модели потоков ядра со своей спецификой реализованы в следующих ОС:

  • Windows 95/98/NT/2000/XP/2003/2008/7;
  • Solaris;
  • Tru64 UNIX;
  • BeOS;
  • Linux.

Существуют различные модели многопоточности – способы отображения пользовательских потоков в потоки ядра. Теоретически возможны (и на практике реализованы) следующие модели многопоточности:

Модель много / один (many-to-one) – отображение нескольких пользовательских потоков в один и тот же поток ядра. Используется в операционных системах, не поддерживающих множественные системные потоки (например, с целью экономии памяти). Данная модель изображена на рис. 10.2 .

Рис. 10.2. Схема модели многопоточности "много / один".

Модель один / один (one-to-one) – взаимно-однозначное отображение каждого пользовательского потока в определенный поток ядра. Примеры ОС, использующих данную модель, - Windows 95/98/NT/2000/XP/2003/2008/7; OS/2. Данная модель изображена на рис. 10.3 .

Рис. 10.3. Схема модели многопоточности "один / один".

Модель много / много (many-to-many) – модель, допускающая отображение нескольких пользовательских потоков в несколько системных потоков. Такая модель позволяет ОС создавать большое число системных потоков. Характерным примером ОС, использующей подобную модель, является ОС Solaris, а также Windows NT / 2000 / XP / 2003 / 2008 / 7 с пакетом ThreadFiber . Данная модель изображена на рис. 10.4 .

Рис. 10.4. Схема модели многопоточности "много / много".

Конец работы -

Эта тема принадлежит разделу:

В лекции рассматриваются понятие потока thread и многопоточное выполнение multi-threading

В лекции рассматриваются понятие потока thread и многопоточное выполнение multi threading модели многопоточности пользовательские потоки и.. содержание введение однопоточные и многопоточные процессы история многопоточности пользовательские..

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

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

Однопоточные и многопоточные процессы
К сожалению, до сих пор мышление многих программистов при разработке программ остается чисто последовательным. Не учитываются широкие возможности параллелизма, в частности, многопоточности. Последо

История многопоточности
Как небезынтересно отметить, один из первых шагов на пути к широкому использованию многопоточности, по-видимому, был сделан в 1970-е годы советскими разработчиками компьютерной аппаратуры и програм

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

Потоки и процессы в Solaris
В ОС Solaris, как уже было отмечено, используется модель потоков много / много. Кроме того, в системе используется также уже известное нам понятие облегченный процесс (ligh

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

Ключевые термины
Mac C-threads – пользовательские потоки в системе MacOS. POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX-приложениях. Solaris threads – пользова

Модель много / много- модель многопоточности,при которой различные пользовательские потокимогут быть отображены в различные потоки ядра
Модель много / один- модель многопоточности, при которой несколько пользовательских потоковмогут быть отображены в один поток ядра

Краткие итоги
Многопоточность (multi-threading) – современное направление программирования, особенно актуальное в связи с широким распространением параллельных компьютерных архитектур. Поток – особый вид процесс

Вопросы
Что такое поток? Чем отличаются однопоточные и многопоточные процессы? В чем преимущества многопоточности? В какой системе впервые было реализовано понятие процесса

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

Темы для курсовых работ, рефератов, эссе
История концепции потока и многопоточности в операционных системах и языках программирования (реферат). Обзор многопоточности в UNIX, Linux, Solaris (реферат). Обзор многопо

Однопоточные и многопоточные процессы

К сожалению, до сих пор мышление многих программистов при разработке программ остается чисто последовательным. Не учитываются широкие возможности параллелизма , в частности, многопоточности. Последовательный (однопоточный) процесс – это процесс, который имеет только один поток управления (control flow ), характеризующийся изменением его счетчика команд . Поток (thread) – это запускаемый из некоторого процесса особого рода параллельный процесс, выполняемый в том же адресном пространстве, что и процесс-родитель.

Рис. 10.1. Однопоточный и многопоточный процессы.

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

Многопоточность имеет большие преимущества:

· Увеличение скорости (по сравнению с использованием обычных процессов). Многопоточность основана на использовании облегченных процессов (lightweight processes) ,работающих в общем пространстве виртуальной памяти. Благодаря многопоточности, не возникает больше неэффективных ситуаций, типичных для классической системы UNIX, в которой каждая команда shell (даже команда вывода содержимого текущей директории ls исполнялась как отдельный процесс , причем в своем собственном адресном пространстве. В противоположность облегченным процессам, обычные процессы (имеющие собственное адресное пространство) часто называют тяжеловесными (heavyweight) .

· Использование общих ресурсов . Потоки одного процесса используют общую память и файлы.

· Экономия . Благодаря многопоточности, достигается значительная экономия памяти, по причинам, объясненным выше. Также достигается и экономия времени, так как переключение контекста на облегченный процесс, для которого требуется только сменить стек и восстановить значения регистров, значительно быстрее, чем на обычный процесс.

Использование мультипроцессорных архитектур . Это особенно важно в настоящее время, в период широкого использования многоядерных гибридных и многопроцессорных систем. Именно многопоточность программ, основанная на многоядерности процессора, дает возможность, наконец, почувствовать реальные преимущества параллельного выполнения.

История многопоточности

Как небезынтересно отметить, один из первых шагов на пути к широкому использованию многопоточности, по-видимому, был сделан в 1970-е годы советскими разработчиками компьютерной аппаратуры и программистами. МВК "Эльбрус-1", разработанный в 1979 году, поддерживал в аппаратуре и операционной системе эффективную концепцию процесса, которая была близка к современному понятию облегченного процесса. В частности, процесс в "Эльбрусе" однозначно характеризовался своим стеком. Иначе говоря, все процессы были облегченными и исполнялись в общем пространстве виртуальной памяти – других процессов в "Эльбрусе" просто не было!

Концепция многопоточности начала складываться, по-видимому, с 1980-х гг. в системе UNIX и ее диалектах. Наиболее развита многопоточность была в диалекте UNIX фирмы AT&T, на основе которого, как уже отмечалось в общем историческом обзоре, была разработана система Solaris. Все это отразилось и в стандарте POSIX , в который вошла и многопоточность, наряду с другими базовыми возможностями UNIX .

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

По-видимому, именно по причине различий в спецификациях и реализациях многопоточности в различных системах профессор Бьярн Страуструп не включил многопоточность в созданный им язык C++, ставший столь популярным, и его базовый набор библиотек. Программисты на языке C++ были вынуждены по-прежнему использовать многопоточность на уровне системных вызовов и библиотек конкретных операционных систем.

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

Платформа.NET , появившаяся в 2000 г., предложила свой механизм многопоточности, который фактически является развитием идей Java .

Различие подходов к многопоточности в разных ОС и на разных платформах разработки программ сохраняется и до настоящего времени, что приходится постоянно учитывать разработчикам. Для прикладных программ мы рекомендуем реализовывать многопоточность на платформе Java или.NET , что наиболее удобно и позволяет использовать высокоуровневые понятия и конструкции. Однако в нашем курсе, посвященном операционным системам, мы, естественно, больше внимания уделяем системным вопросам многопоточности и ее реализации в операционных системах.

Пользовательские потоки и потоки ядра

Модели многопоточности .Реализация многопоточности в ОС, как и многих других возможностей, имеет несколько уровней абстракции. Самый высокий из них – пользовательский уровень. С точки зрения пользователя и его программ, управление потоками реализовано через библиотеку потоков пользовательского уровня (user threads) Подробнее конкретные операции над пользовательскими потоками будут рассмотрены немного позже. Пока отметим лишь, что существует несколько моделей потоков пользовательского уровня, среди которых:

· POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX -приложениях (рассмотрены позже в данной лекции);

· Mac C-threads – пользовательские потоки в системе MacOS;

· Solaris threads – пользовательские потоки в ОС Solaris (рассмотрены позже в данной лекции).

Низкоуровневые потоки, в которые отображаются пользовательские потоки, называются потоками ядра (kernel threads) .Они поддержаны и используются на уровне ядра операционной системы. Как и подходы к пользовательским потокам, подходы к архитектуре и реализации системных потоков и к отображению пользовательских потоков в системные в разных ОС различны. Например, собственные модели потоков ядра со своей спецификой реализованы в следующих ОС:

· Windows 95 /98/NT/2000/XP/2003/2008/7;

· BeOS ;

Существуют различные модели многопоточности – способы отображения пользовательских потоков в потоки ядра. Теоретически возможны (и на практике реализованы) следующие модели многопоточности:

Модель много / один (many-to-one) отображение нескольких пользовательских потоков в один и тот же поток ядра. Используется в операционных системах, не поддерживающих множественные системные потоки (например, с целью экономии памяти).

Рис. 10.2. Схема модели многопоточности "много / один".

Модель один / один (one-to-one) – взаимно-однозначное отображение каждого пользовательского потока в определенный поток ядра. Примеры ОС, использующих данную модель, - Windows 95 /98/NT/2000/XP/2003/2008/7; OS/2 .

Рис. 10.3. Схема модели многопоточности "один / один".

Модель много / много (many-to-many) – модель, допускающая отображение нескольких пользовательских потоков в несколько системных потоков. Такая модель позволяет ОС создавать большое число системных потоков. Характерным примером ОС, использующей подобную модель, является ОС Solaris, а также Windows NT / 2000 / XP / 2003 / 2008 / 7 с пакетом ThreadFiber .

Рис. 10.4. Схема модели многопоточности "много / много".

Проблемы многопоточности

Многопоточность – весьма сложная, еще не полностью изученная и, тем более, не полностью формализованная область, в которой имеется много интересных проблем. Рассмотрим некоторые из них.

Семантика системных вызовов fork() и exec() .Как уже отмечалось, вклассической ОС UNIX системный вызов fork создает новый "тяжеловесный" процесс со своим адресным пространством, что значительно "дороже", чем создание потока. Однако, с целью поддержания совместимости программ снизу вверх, приходится сохранять эту семантику, а многопоточность вводить с помощью новых системных вызовов.

Прекращение потоков . Важной проблемой является проблема прекращения потоков: например, если родительский поток прекращается, то должен ли при этом прекращаться дочерний поток ? Если прекращается стандартный процесс, создавший несколько потоков, то должны ли прекращаться все его потоки? Ответы на эти вопросы в разных ОС неоднозначны.

Обработка сигналов . Сигналы в UNIX – низкоуровневый механизм обработки ошибочных ситуаций. Примеры сигналов: SIGSEGV - нарушение сегментации (обращение по неверному адресу, чаще всего по нулевому); SIGKILL – сигнал процессу о выполнении команды kill его уничтожения. Пользователь может определить свою процедуру-обработчик сигнала системным вызовом signal . Проблема в следующем: как распространяются сигналы в многопоточных программах и каким потоком они должны обрабатываться? В большинстве случаев этот вопрос решается следующим образом: сигнал обрабатывается потоком, в котором он сгенерирован, и влияет на исполнение только этого потока. В более современных ОС (например, Windows 2000 и более поздних версиях Windows ), основанных на объектно-ориентированной методологии, концепция сигнала заменена более высокоуровневой концепцией исключения (exception) .Исключение распространяется по стеку потока в порядке, обратном порядку вызовов методов, и обрабатывается первым из них, в котором система находит подходящий обработчик. Аналогичная схема обработки исключений реализована в Java и в.NET .

Группы потоков . В сложных задачах, например, задачах моделирования, при большом числе разнородных потоков, возникает потребность в их структурировании с помощью концепции группы потоков – совокупности потоков, имеющей свое собственное имя, над потоками которой определены групповые операции . Наиболее удачно, с нашей точки зрения, группы потоков реализованы в Java (с помощью классаThreadGroup ). Следует отметить также эффективную реализацию пулов потоков (ThreadPool) в.NET .

Локальные данные потока (thread-local storage - TLS) – данные, принадлежащие только определенному потоку и используемые только этим потоком. Необходимость в таких данных очевидна, так как многопоточность – весьма важный метод распараллеливания решения большой задачи, при котором каждый поток работает над решением порученной ему части. Все современные операционные системы и платформы разработки программ поддерживают концепцию локальных данных потока.

Синхронизация потоков . Поскольку потоки, как и процессы могут использовать общие ресурсы и реагировать на общие события, необходимы средства их синхронизации. Эти средства подробно рассмотрены позже в данном курсе.

Тупики (deadlocks) и их предотвращение . Как и процессы, потоки могут взаимно блокировать друг друга (т.е. может создаться ситуация deadlock ), при их неаккуратном программировании. Меры по борьбе с тупиками подробно рассмотрены позже в данном курсе.

Потоки POSIX (Pthreads)

В качестве конкретной модели многопоточности рассмотрим потоки POSIX (напомним, что данная аббревиатура расшифровывается как Portable Operating Systems Interface of uniX kind – стандарты дляпереносимых ОС типа UNIX ). Многопоточность в POSIX специфицирована стандартом IEEE 1003.1c, который описывает API для создания и синхронизации потоков . Отметим, что POSIX -стандарт API определяет лишь требуемое поведение библиотеки потоков. Реализация потоков оставляется на усмотрение авторов конкретной POSIX -совместимой библиотеки. POSIX -потоки распространены в ОС типа UNIX , а также поддержаны, с целью совместимости программ, во многих других ОС, например, Solaris и Windows NT.

Стандарт POSIX определяет два основных типа данных для потоков: pthread_t – дескриптор потока ; pthread_attr_t – набор атрибутов потока .

Стандарт POSIX специфицирует следующий набор функций для управления потоками :

· pthread_create(): создание потока

· pthread_exit():завершение потока (должна вызываться функцией потока при завершении)

· pthread_cancel():отмена потока

· pthread_join():заблокировать выполнение потока до прекращения другого потока, указанного в вызове функции

· pthread_detach():освободить ресурсы занимаемые потоком (если поток выполняется, то освобождение ресурсов произойдёт после его завершения)

Отличие от процессов

Потоки выполнения отличаются от традиционных процессов многозадачной операционной системы тем, что:

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

Многопоточность

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

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

Другим использованием многопоточности, применяемым даже для однопроцессорных систем, является возможность для приложения реагирования на ввод данных. В однопоточных программах, если основной поток выполнения заблокирован выполнением длительной задачи, всё приложение может оказаться в замороженном состоянии. Перемещая такие длительные задачи в рабочий поток , который выполняется параллельно с основным потоком, становится возможным для приложений продолжать реагировать на действия пользователя во время выполнения задач в фоновом режиме. С другой стороны, в большинстве случаев многопоточность не единственный способ сохранить чувствительность программы. То же самое может быть достигнуто через асинхронный ввод/вывод или сигналы в UNIX.

Операционные системы планируют выполнение потоков одним из двух способов:

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

До конца 1990-х процессоры в настольных компьютерах не имели поддержки многопоточности, так как переключение между потоками, как правило, происходило быстрее, чем полное переключение контекста процесса. Процессоры во встраиваемых системах , которые имеют более высокие требования к поведению в реальном времени , могут поддерживать многопоточность за счёт уменьшения времени на переключение между потоками, возможно, путём распределения выделенных регистровых файлов для каждого потока выполнения, вместо сохранения/восстановления общего регистрового файла. В конце 1990-х идея выполнения инструкций нескольких потоков одновременно, известная как одновременная многопоточность, под названием Hyper-Threading, достигла настольных компьютеров с процессором Intel Pentium 4 . Потом она была исключена из процессоров архитектуры Intel Core и Core 2 , но позже восстановлена в архитектуре Core i7 .

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

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

Процессы, потоки выполнения ядра, пользовательские потоки и файберы

Процесс является «самой тяжёлой» единицей планирования ядра. Собственные ресурсы для процесса выделяются операционной системой. Ресурсы включают память, дескрипторы файлов, разъёмы, дескрипторы устройств и окна. Процессы используют адресное пространство и файлы ресурсов в режиме разделения времени только через явные методы, такие как наследование дескрипторов файлов и сегментов разделяемой памяти. Процессы, как правило, предварительно преобразованы к многозадачному способу выполнения.

Потоки выполнения ядра относятся к «лёгким» единицам планирования ядра. Внутри каждого процесса существует по крайней мере один поток выполнения ядра. Если в рамках процесса могут существовать несколько потоков выполнения ядра, то они совместно используют общую память и файл ресурсов. Если процесс выполнения планировщика операционной системы является приоритетным, то потоки выполнения ядра тоже являются приоритетно многозадачными. Потоки выполнения ядра не имеют собственных ресурсов, за исключением стека вызовов , копии регистров процессора , включая счётчик команд , и локальную память потока выполнения (если она есть). Ядро может назначить по одному потоку выполнения для каждого логического ядра системы (поскольку каждый процессор разделяет сам себя на несколько логических ядер, если он поддерживает многопоточность, либо поддерживает только одно логическое ядро ​​на каждое физическое ядро, если не поддерживает многопоточность), а может выполнять свопинг заблокированных потоков выполнения. Однако потоки выполнения ядра требует гораздо больше времени, чем требуется на свопинг пользовательских потоков выполнения.

Потоки выполнения иногда реализуются в пользовательском пространстве библиотек, в этом случае они называются пользовательскими потоками выполнения . Ядро не знает о них, так что они управляются и планируются в пользовательском пространстве. В некоторых реализациях пользовательские потоки выполнения основываются на нескольких верхних потоках выполнения ядра , чтобы использовать преимущества многопроцессорных машин (модели M:N). В данной статье под термином «поток выполнения» по умолчанию (без квалификатора «ядра» или «пользовательский») имеется в виду «поток выполнения ядра». Пользовательские потоки выполнения, реализованные с помощью виртуальных машин , называют также «зелёными потоками выполнения». Пользовательские потоки выполнения, как правило, можно быстро создавать, и ими легко управлять, но они не могут использовать преимущества многопоточности и многопроцессорности. Они могут блокироваться, если все связанные с ним потоки выполнения ядра заняты, даже если некоторые пользовательские потоки готовы к запуску.

Файберы являются ещё более «лёгкими» блоками планирования, относящимися к кооперативной многозадачности : выполняющийся файбер должен явно «уступить» право другим файберам на выполнение, что делает их реализацию гораздо легче, чем реализацию потоков выполнения ядра ​​или пользовательских потоков выполнения. Файберы могут быть запланированы для запуска в любом потоке выполнения внутри того же процесса. Это позволяет приложениям получить повышение производительности за счет управления планированием самого себя, вместо того чтобы полагаться на планировщик ядра (который может быть не настроен на такое применение). Параллельные среды программирования, такие как OpenMP , обычно реализуют свои задачи посредством файберов.

Сущность потока выполнения и файбера

Одновременность и структуры данных

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

Чтобы избежать этого, прикладные программные интерфейсы (API) потоков выполнения предлагают примитивы синхронизации , такие как мьютексы , для блокировки структур данных от одновременного доступа. На однопроцессорных системах поток выполнения, обратившийся к заблокированному мьютексу, должен остановить работу и, следовательно, инициировать переключение контекста. На многопроцессорных системах поток выполнения может вместо опроса мьютекса произвести захват спинлока . Оба этих способа могут снижать производительность и вынуждать процессор в SMP-системах конкурировать за шину памяти, особенно если уровень модульности блокировок слишком высокий.

Ввод/вывод и планирование

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

Однако использование блокировок системных вызовов для пользовательских потоков выполнения (в отличие от потоков выполнения ядра) и файберов имеет свои проблемы. Если пользовательский поток выполнения или файбер выполняет системный вызов, другие потоки выполнения и файберы процесса не могут работать до завершения этой обработки. Типичный пример такой проблемы связан с выполнением операций ввода/вывода. Большинство программ рассчитаны на синхронное выполнение ввода/вывода. При инициации ввода/вывода делается системный вызов, и он не возвращается до его завершения. В промежутке весь процесс блокируется ядром и не может исполняться, лишая возможности работы другие пользовательские потоки и файберы этого процесса.

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

N:1 (потоки выполнения уровня пользователя)

В модели N:1 предполагается, что все потоки выполнения уровня пользователя отображаются на единую планируемую сущность уровня ядра, и ядро ничего не знает о составе прикладных потоков выполнения. При таком подходе переключение контекста может быть сделано очень быстро, и, кроме того, он может быть реализован даже на простых ядрах, которые не поддерживают многопоточность. Однако, одним из главных недостатков его является то, что в нём нельзя извлечь никакой выгоды из аппаратного ускорения на многопоточных процессорах или многопроцессорных компьютерах, потому что только один поток выполнения может быть запланирован на любой момент времени. Эта модель используется в GNU Portable Threads.

M:N (смешанная потоковость)

В модели M:N некоторое число N прикладных потоков выполнения отображаются на некоторое число M сущностей ядра или «виртуальных процессоров». Модель является компромиссной между моделью уровня ядра («1:1») и моделью уровня пользователя («N:1»). Вообще говоря, «M:N» потоковость системы являются более сложной для реализации, чем ядро или пользовательские потоки выполнения, поскольку изменение кода как для ядра, так и для пользовательского пространства не требуется. В M:N реализации библиотека потоков отвечает за планирование пользовательских потоков выполнения на имеющихся планируемых сущностях. При этом переключение контекста потоков делается очень быстро, поскольку модель позволяет избежать системных вызовов. Тем не менее, увеличивается сложность и вероятность инверсии приоритетов, а также неоптимальность планирования без обширной (и дорогой) координации между пользовательским планировщиком и планировщиком ядра.

Реализации

Есть много различных, несовместимых друг с другом реализаций потоков. К ним относятся как реализации на уровне ядра, так и реализации на пользовательском уровне. Чаще всего они придерживаются более или менее близко стандарта интерфейса POSIX Threads .

Примеры реализаций потоков на уровне ядра

  • Light Weight Kernel Threads (LWKT) в различных версиях BSD
  • Потоковость MxN
  • Библиотека потоков POSIX (NPTL) для Linux , реализация стандарта POSIX Threads
  • Apple Multiprocessing Services, врсия 2.0 и последующие, использует встроенное микроядро в Mac OS 8.6, в более поздних версиях сделана модификация с целью последующего сопровождения.
  • Windows начиная с Windows 95 , Windows NT и после них.

Примеры реализаций потоков на уровне пользователя

  • GNU Portable Threads
  • FSU Pthreads
  • Thread Manager компании Apple
  • REALbasic (включая API для совместного использования потоков)
  • Netscape Portable Runtime (включая реализацию файберов в пользовательском пространстве)

Примеры реализаций смешанных потоков

  • «Scheduler activations» используется в собственной библиотеке приложений потоков POSIX для NetBSD (модель M:N в противоположность модели 1:1 ядра или модели приложений пользовательского пространства)
  • Marcel из проекта PM2
  • ОС для суперкомпьютера Tera/Cray MTA

Примеры реализаций файберов

Файберы могут быть реализованы без поддержки операционной системы, хотя некоторые операционные системы и библиотеки предоставляют явную поддержку для них.

Поддержка языков программирования

Многие языки программирования поддерживают потоки иначе. Большинство реализаций С и С++ сами по себе не обеспечивают прямой поддержки потоков, но обеспечивают доступ к потокам, предоставляемым операционной системой, через API. Некоторые языки программирования более высокого уровня (как правило, кросс-платформенные), такие как Java, Python, и.NET, предоставляют потоковость разработчику в виде абстрактной специфической платформы, отличающейся от реализации потоков в среде выполнения разработчика. Ряд других языков программирования также пытаются полностью абстрагировать концепцию параллелизма и потоковости от разработчика (Cilk , OpenMP , MPI …). Некоторые языки разрабатываются специально для параллелизма (Ateji PX, CUDA).

Некоторые интерпретирующие языки программирования, такие как Руби и CPython (реализация Python) поддерживают потоки, но имеют ограничение, которое известно как глобальная блокировка интерпретатора (GIL). GIL является взаимной блокировкой исключений, выполняемых интерпретатором, которая может уберечь интерпретатор от одновременной интерпретации кода приложений в двух или более потоках одновременно, что фактически ограничивает параллелизм на многоядерных системах (в основном для потоков, связанных через процессор, а не для потоков, связанных через сеть).

См. также

Примечания

Литература

  • David R. Butenhof. Programming with POSIX Threads. Addison-Wesley. ISBN 0-201-63392-2
  • Bradford Nichols, Dick Buttlar, Jacqueline Proulx Farell. Pthreads Programming. O’Reilly & Associates. ISBN 1-565-92115-1
  • Charles J. Northrup. Programming with UNIX Threads. John Wiley & Sons. ISBN 0-47-113751-0
  • Mark Walmsley. Multi-Threaded Programming in C++. Springer. ISBN 1-852-33146-1
  • Paul Hyde. Java Thread Programming. Sams. ISBN 0-67-231585-8
  • Bill Lewis. Threads Primer: A Guide to Multithreaded Programming. Prentice Hall. ISBN 0-13-443698-9
  • Steve Kleiman, Devang Shah, Bart Smaalders. Programming With Threads, SunSoft Press. ISBN 0-13-172389-8
  • Pat Villani. Advanced WIN32 Programming: Files, Threads, and Process Synchronization. Harpercollins Publishers. ISBN 0-87-930563-0
  • Jim Beveridge, Robert Wiener. Multithreading Applications in Win32. Addison-Wesley. ISBN 0-20-144234-5
  • Thuan Q. Pham, Pankaj K. Garg. Multithreaded Programming with Windows NT. Prentice Hall. ISBN 0-13-120643-5
  • Len Dorfman, Marc J. Neuberger. Effective Multithreading in OS/2. McGraw-Hill Osborne Media. ISBN 0-07-017841-0
  • Alan Burns, Andy Wellings. Concurrency in ADA. Cambridge University Press. ISBN 0-52-162911-X
  • Uresh Vahalia. Unix Internals: the New Frontiers. Prentice Hall. ISBN 0-13-101908-2
  • Alan L. Dennis. .Net Multithreading. Manning Publications Company. ISBN 1-930-11054-5
  • Tobin Titus, Fabio Claudio Ferracchiati, Srinivasa Sivakumar, Tejaswi Redkar, Sandra Gopikrishna. C# Threading Handbook. Peer Information. ISBN 1-861-00829-5
  • Tobin Titus, Fabio Claudio Ferracchiati, Srinivasa Sivakumar, Tejaswi Redkar, Sandra Gopikrishna. Visual Basic .Net Threading Handbook. Wrox Press. ISBN 1-861-00713-2

Ссылки

  • Binildas C. A. Query by Slice, Parallel Execute, and Join: A Thread Pool Pattern in Java
  • Herb Sutter. The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software
  • Multithreading в каталоге ссылок Open Directory Project (dmoz).
  • Daniel Robbins. POSIX threads explained


Онлайн калькуляторы