Oc-windows.ru

IT Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Thread safety php

Thread safety php

When PHP is built with Thread Safety enabled, the engine requires a way to isolate contexts from one another, such that the threads of a process may service individual requests without interference. TSRM is omnipotent within PHP, extension authors have to do very little in order to make sure their extensions can function in both a Thread Safe and Non Thread Safe architecture.

Example #1 Accessor macros for per-module globals

The snippet above shows how an extension author is expected to define their global accessors. The TSRMG macro takes an identifier, type cast and element name. The identifier is assigned by TSRM during initialization of the module. Declaring global accessors in this way ensures that an extension can operate safely in a Thread Safe and Non Thread Safe architecture using the same logic.

TSRM manages the isolation and safety of all global structures within PHP, from executor globals to extension globals, a pointer to the isolated storage is also passed around with most, or many of the API functions. The macros TSRMLS_C and TSRMLS_CC translate to «thread safe local storage» and «thread safe local storage prefixed with a comma» respectively.

If a function requires a pointer to TSRM, it is declared with the macro TSRMLS_D or TSRMLS_DC in it’s prototype, which translates to «thread safe local storage only» and «thread safe local storage prefixed with a comma» respectively. Many macros within the engine reference TSRM, so it is a good idea to declare most things to accept TSRM, such that if they need to call upon TSRM they do not have to fetch a pointer during execution.

Because TSRM is thread local, and some functions (for compatibility reasons) are not able to accept TSRM directly, the macro TSRMLS_FETCH exists, which requests that TSRM fetches the pointer to the thread local storage. This should be avoided wherever it can be, as it is not without cost in a Thread Safe setup.

Note: While developing extensions, build errors that contain «tsrm_ls is undefined» or errors to that effect stem from the fact that TSRMLS is undefined in the current scope, to fix this, declare the function to accept TSRMLS with the appropriate macro, if the prototype of the function in question cannot be changed, you must call TSRMLS_FETCH within the function body.

The functionality documented hereafter is aimed at advanced use of TSRM. It is not ordinary for extensions to have to interact with TSRM directly, the pecl programmer should use API’s above TSRM such as the Module Globals API.

TSRM Internals

PrototypeDescription
typedef int ts_rsrc_idThe type definition to represent a resource by numeric identifiers
int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename)expected_threads and expected_resources are not hard limits. debug_level and debug_filename only have an effect on windows in Debug mode or when TSRM_DEBUG is defined. Called once per process in ZTS mode during server startup.
void tsrm_shutdown(void)Should be the last thing called in the process to destroy and free all storage TSRM storage in ZTS mode.
ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)Allocates and thread safe pointer of size bytes, calling ctor on the pointer, assigning (and returning) the >rsrc_id , the dtor is called when the resource is free’d. Module globals are isolated in ZTS mode using this API.
void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)Fetches a resource by previously allocated id from the entries created by the specified thread >th_id .
void *ts_resource(ts_rsrc_id id)Fetches a resource by previously allocated id from the entries created by the calling thread.
void ts_free_thread(void)Destroys and frees the entries for the calling thread, currently this API is only used by ISAPI module.
void ts_free_id(ts_rsrc_id id)Destroys the resource >id . Module globals are cleaned up in ZTS mode using this API.

Note: There are more TSRM API functions to enable the creation and destruction of interpreter contexts, the usage of such functionality is out of the scope of this documentation, please see TSRM/TSRM.h for more information.

TSRM Mutex API

PrototypeDescription
MUTEX_T tsrm_mutex_alloc(void)Allocates and returns a suitable MUTEX_T for the environment.
int tsrm_mutex_lock(MUTEX_T mutexp)Locks mutexp for the calling thread.
int tsrm_mutex_unlock(MUTEX_T mutexp)Unlocks mutexp for the calling thread.
void tsrm_mutex_free(MUTEX_T mutexp);Destroys and frees the (unlocked) and previously allocated mutexp .

Note: The mutex API is exposed by TSRM. However, its internal usage is far too wide to document usefully here, none the less, basic functionality and prototypes are documented here.

Thread safety php

Прелесть open-source кода в его открытости :)) Т.е. при наличии ума/времени/желания можно разобраться, как именно работает программа. Обратная сторона такого кода — сложность в получении нужных скомпилированных пакетов. Например, PHP можно скачать в виде исходников для Nix-систем с последующей компиляцией/сборкой. Для Windows все уже собрано, но готовых бинарных пакетов много! Варианты с «thread safe/non thread safe«, VC6/VC9 и разные версии самого PHP. Статья создана для прояснения ситуации. В основе — разные источники, частично — перевод с английского. Все для того, чтоб в следующий раз мне опять не разбираться — «че к чему!?».

Нужная версия PHP зависит от версии веб-сервера, на котором он будет использоваться. Например, Apache 1.3.x работает с РНР версии 3.0.х, Apache 2.х работает с РНР версии 4.0 и выше. Но это не такая уж проблема, ориентируйтесь на более новые стабильные релизы и то, что стоит у хостера.

Что за приписки VC6, VC9, VC11? Исходники PHP под Windows компилируются в Visual Studio. VC9 получается при компиляции в VS 2008, VC11 — Visual Studio 2012. Соответственно, чтобы все это дело у вас работало, на компе должны быть установлены библиотеки Visual C++ Redistributable for Visual Studio соответствующего года. Некоторые разъяснения по этому поводу здесь.

Кроме того, если web-сервером у вас будет старенький Apache с сайта apache.org, то нужно качать VC6 версии PHP, для компиляции которых использовался Visual Studio 6. Если же PHP будет работать для IIS или в связке с более новым Apache, то можно собрать что-нибудь посовременнее 😉

Для меня главным ступором в выборе служит хостер. Сейчас есть стабильная версия PHP 5.5.4, а у него до сих пор 5.2.17!

Теперь самая интересная часть: «thread safe or non thread safe?»
Вольный перевод статьи Difference between PHP thread safe and non thread safe binaries (Dominic Ryan, 27.09.2007)

Я настолько ломанного английского еще не видел :(( Хотел по-быстрому перевести статью, но с трудом понимаю, что автор понаписал. Постоянные переходы между «what-is-that» и сложно-составные предложения вообще выносят мОСк. Перевод на русский так же осложняется тем, что у меня не хватает знаний и фантазии как правильно по-русски должно называться то, что обычно пишется только на английском %) Например техническое понятие «multi proccess architecture» я ни разу не видел на русском, а мой перл «потоко-небезопасные» вообще под вопросом здравого смысла. Вообщем, что получилось, то привожу.

Разница между thread safe и non thread safe бинарными пакетами PHP

С тех пор, когда PHP впервые появился под Windows 20 октября 2000 года в версии PHP 3.0.17, его бинарные пакеты всегда были собраны как потоко-безопасные (thread safe, TS). Основание следующее: Windows использует мульти-поточную архитектуру работы, а Nix-системы поддерживают мульти-процессовую архитектуру. Если PHP был скомпилирован как мульти-процессовое CGI-приложение вместо мульти-поточного, то его использование в качестве CGI-модуля под Windows на сервере IIS приводит к сильным тормозам и загрузке процессора. С другой стороны, можно подключить PHP на IIS, как ISAPI-модуль (требуется мульти-поточная сборкаприм. переводчика). Тогда возникает другая проблема: некоторые популярные расширения PHP разработаны с ориентиром на Unix/Linux, т.е. с мульти-процессовой архитектурой, что приводит к краху PHP, подключенному на IIS в качестве ISAPI-модуля. Т.о. создание CGI — наиболее стабильная среда для PHP на IIS с основным недостатком, что это ужасно медленно. Приходится загружать и выгружать всю среду PHP из памяти каждый раз, когда есть запрос.

В то время было несколько вариантов для увеличения производительности PHP на IIS. Первый — использовать кеширование опкода программами типа eAccelerator, которые сохраняют PHP-скрипты в частично скомпилированном состоянии на диске и/или в памяти. Такой подход значительно сокращает время выполнения скрипта. Другой вариант заключался в настройке IIS на использование PHP в режиме FastCGI. При этом PHP-процесс после отработки не закрывался, а получал новое задание с очередным php-запросом. К тому же можно было запустить несколько PHP-процессов одновременно, ощутимо ускоряя обработку запросов, что являлось бонусом CGI-режима PHP. При этом могли быть незначительные проблемы с совместимостью PHP-расширений. Это по-прежнему самый быстрый способ использования PHP, и именно на задание такой конфигурации IIS настроен установщик «IIS Aid PHP Installer».

Бинарники, собранные в потоко-небезопасном режиме (non thread safe, NTS), позволяют сконфигурировать IIS (и другие веб-сервера под Windows) на использование PHP, как стандартный CGI-интерфейс с сильным приростом производительности, т.к. в этом случае (в такой сборке) PHP-процессу не нужно дожидаться синхронизации нитей. При сравнении работы «thread safe» и «non thread safe» бинарных пакетов PHP на IIS в качестве стандартного CGI-интерфейса прирост быстродействия составляет до 40%, но это все равно не так шустро как использование опкода в FastCGI методе. А самый большой косяк в том, что нельзя стабильно использовать потоко-небезопасные бинарники вместе с потоко-безопасными. Это значит, что вы не можете использовать системы кеширования опкода типа eAccelerator в среде PHP, созданной потоко-небезопасными бинарными пакетами (утверждение, верное на момент написания статьи).

Если потоко-небезопасный PHP нельзя сконфигурировать до такой же скорости, что и потоко-безопасную среду, то зачем он нужен в такой сборке? Возвращаемся к FastCGI и разработкам Microsoft в этой области за последние несколько лет. Кодеры мелкомягких создали свой вариант FastCGI, который позволяет конфигурировать потоко-небезопасные бинарники PHP в режиме FastCGI, что доводит производительность до скорости света 🙂

Из статьи я сделал вывод, что тормоза наблюдаются только при использовании с веб-сервером IIS. В любом случае, тупняков под Windows+Apache я не видел. В ней же сказано, что можно разогнать NTS-сборку на любом веб-сервере, но я не представляю себе такой конфиг Apache.

Понравилась статья? Расскажите о ней друзьям:

php thread safe vs non

Подскажите в чём прелесть и недостаток каждого из вариантов?

Thread Safety means that binary can work in a multithreaded webserver context, such as Apache 2 on Windows. Thread Safety works by creating a local storage copy in each thread, so that the data won’t collide with another thread.

So what do I choose? If you choose to run PHP as a CGI binary, then you won’t need thread safety, because the binary is invoked at each request. For multithreaded webservers, such as IIS5 and IIS6, you should use the threaded version of PHP.

Вот как бы в чём вопрос. Везде упоминают Windows для Thread Safety.

А что под линуксом например всё равно, что использовать с ПХП?

Или во фразе: Thread Safety means that binary can work in a multithreaded webserver context, such as Apache 2 on Windows. Вместо «Windows» можно подставить другую операционку?

под линуксом, на сколько я могу судить, всё равно.

Я ещё забыл упомянуть, что есть некоторые расширения, которые требуют Thread-safe сборку (например, pthreads), но их немного и я не слышал, чтобы их кто-то реально использовал.

Вместо «Windows» можно подставить другую операционку?

Да и нет. Дело в том, что апач под linux обычно работает в виде отдельных процессов, а не многопоточно, и это общая практика в unix-системах, классика, а «such as Apache 2 on Windows» это именно особый случай, когда апач работает только многопоточно, такова специфика оффтопика, поэтому они его в пример и приводят. Но в принципе, можно и в linux запускать апач в многопоточном режиме.

Я может чего-то подзабыл. чем отличаются потоки от процессов на программном уровне? И как каждый из них переводится на английский? 🙂

Наверное имеется ввиду что мултипоточность — это когда каждый работает в своей виртуальной памяти и не имеет никакого доступа к другому (даже не знает о нем) за счет аппаратного i386 режима.

Тогда не понятно какое имеет отношение к этому сам аппач. Хотя наверное я переставил местами потоки и процессы.

Тоесть если использовать thread safe, то в любом случае будет ок? Или как?

чем отличаются потоки от процессов на программном уровне

Тем что потоки работают в одном и том же адресном пространстве, а процессы — каждый в своём

Тогда не понятно какое имеет отношение к этому сам аппач

Тем что при множестве процессов, в рамках одного процесса программа однопоточна, пых запускается однопоточно и о других процессах ничего не знает, а threadsafe не нужен.

Я выше писал тоже самое и даже упоминал i386 protected mode (аппаратный режим разраничения адресных простарнств).

И да. как и Вы ошибся, потоки (threads), какраз таки в одном постранстве копошатся, а процессы (processes) — это вроде и есть уже разделённые аппаратно процессы.

В виндовсе вроде как сервисы называются, а в линуксе — демоны.

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

вопрос вобщем остался таковым. Универсалный ли вариант, если использовать thread safe вариант ПХП?

Что значит как и я? Я тебе как раз правильно рассказал.

есть основной процесс который делает теже потоки и контролирует их

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

Универсалный ли вариант, если использовать thread safe вариант ПХП?

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

Я не совем тогда понимаю, если на сайт зашло 100 человек, они работают в однопотоке? Это вообще реально, удобно и быстро?

threadsafe там запилен конкретно под специфику работы http-серверов в винде

А в линуксе как-то по другому работают потоку? Не понимаю?

нет, просто вместо того чтобы заморачивать себе этим голову, сейчас популярное решение переключиться на связку nginx php fastcgi

Я просто думаю сделать простой сайт визитку.

Мне например вполне хватит Жумлы на ПХП и Апач.

Для ресурсоёмких проектов использую энтерпрайз решения на Жабе.

Глупо поднимать завод по производству урана, если нужна всего лишь распилисть пару досок.

Вот ещё из документации комментарий, не рекомендующий thread safe на продакшн

Моё мнение такое, что если ты не можешь обосновать, зачем тебе включать thread safe, то и делать этого не нужно. В тех же репозиториях убунты лежит non thread safe, которую все поголовно используют и с Apache2 и с nginx. А кейс, когда нужна thread safe версия, надо ещё сперва придумать, сам по себе он внезапно не возникнет.

Мне например вполне хватит Жумлы на ПХП и Апач.

Ну тем более. На тех же шаред хостингах с апачем везде thread safe выключен. И thread safe ты как собрался ставить? Вручную php собирать с экзотическими настройками ради джумлы?

жирновато как то хочешь визитку, а спрашиваешь про трэды

Я про треды не спрашиваю, я про них знаю.

Я не понимаю почему в ПХП так их вынесли как нечто магическое.

Именно и спрашивал в чём плюшки и глюки каждого из вариантов ПХП.

Никто ничего дельного не ответил, зачем именно 2 версии с примерами применения (ну про ЦГИ я почти понял).

Меня интересует именно под апачем как веб применение.

А что жирноватого для визитки из небольшого блога со статьями?

И thread safe ты как собрался ставить? Вручную php собирать с экзотическими настройками ради джумлы?

Вот и расскажите мне нюансы что там не так или тут не эдак.

Я для этого и затеял вопрос?

И причём тут руками сборка для жумлы?

На сайте ПХП есть и та и та версия (уже собранные)

объясните на пальцах чем та или так хороша (плоха) в ве применении на апач.

Апач устаревает, хочешь простоты: почему бы тогда не задействовать встроенный сервер?

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

Может тебе нужно немножко продолжительного рантайма?

Я не собираюсь кодить в ПЫХе

Я собираюсь использовать Joomla

Там есть всё что мне нужно для сайта-визитки и даже больше.

Что за встроенный сервер?

проблема с многопоточностью в php в том, что она есть, но лучше ей не пользоваться. Проблема в исходниках и зависимостях php/расширений PHP. PHP изначально не предназначен для работы в многопоточном режиме. Сам PHP ещё может и потокобезопасен, но вот как быть с сотней расширений, которые используют сторонние C библиотеки, которые хрен знает, как работают в многопоточном режиме, непонятно.

Хотя сейчас,может всё несколько лучше. Но раз разработчики PHP не рекомендуют использовать php в многопоточном режиме, то я предпочитаю им поверить и не использовать.

Не слушай анонимуса, он неадекватен. Это сервер для разработки, а не продакшена (также как simpleHttp в python).

Ставь просто nginx/php5/php-fpm из стандартных репозиториев. Не прогадаешь.

Я не вижу смысла ставить nginx. Если честно, то и опыта работы с ним нет. Не понимаю зачем он нужен для сайта-визитки.

Апач не рекомендуете?

если на сайт зашло 100 человек, они работают в однопотоке

Что значит «зашло»? Для http начхать сколько там зашло, важно сколько они генерируют одновременных запросов. Грубо говоря 100 запросов обрабатываются в 100 однопоточных процессах, если ты про апач. В nginx они просто мултиплексируются в одном процессе.

Это вообще реально, удобно и быстро?

А в линуксе как-то по другому работают потоку?

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

Я не понимаю почему в ПХП так их вынесли как нечто магическое

Да потому и вынесли, что это пляска с бубном, но необходимая, чтобы заводить пых в апаче на винде, а в реальности это нахрен никому не надо.

объясните на пальцах чем та или так хороша

threadsafe ничем не хороша, она просто нужна в апаче на винде и других вариантах, когда пых запускается в многопоточном сервере (т.е. опять же в основном на винде). Причём именно внутри, как с mod_php. Если запускать через fcgi, то threadsafe и на винде не нужен.

Повторение — мать (перемать ) учения 🙂

Изучу глубже отличие организации процессов в линуксе и винде, может пригодится для других случаев в программировании кроме ПХП.

Если честно, раньше был уверен что многопоточность это аппаратная фишка процессоров (i386 protected mode). но наверное перед настройкой дескрипторов и отдачей процу на «жевание» процесса, какие-то есть нюансы например при выделении памяти.

Я уже сталкивался, что в виндовсе и линуксе, как-то по разному организована работа с кучей (heap), например при настройке того же postgresql.

PHP Profi

Квест → Как хакнуть форму

Многопоточное программирование в PHP с помощью Pthreads Перевод

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

В этой статье мы взглянем на то, как многопоточность может быть достигнута в PHP с помощью расширения pthreads. Для этого потребуется установленная ZTS (Zend Thread Safety) версия PHP 7.x, вместе с установленным расширением pthreads v3. (На момент написания статьи, в PHP 7.1 пользователям нужно будет установить из ветки master в репозитории pthreads – см. подробнее как установить (en) стороннее расширение.)

Небольшое уточнение: pthreads v2 предназначена для PHP 5.x и более не поддерживается, pthreads v3 — для PHP 7.х и активно развивается.

Большое спасибо Joe Watkins (создателю расширения pthreads) за вычитку и помощь в улучшении моей статьи!

Когда не стоит использовать pthreads

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

В pthreads v2, рекомендация была в том, что pthreads не должна использоваться в веб-серверной среде (т.е. в fcgi процессе). Что касается pthreads v3, эта рекомендация является программным ограничением, так что теперь вы просто не сможете использовать его в среде веб-сервера. Две известные причины:

  1. Это небезопасно использовать несколько потоков в такой среде (например, в связи с ошибками ввода-вывода, да и кучи других проблем).
  2. Это не очень хорошо масштабируется. Например, скажем, у вас есть PHP-скрипт, который создает новый поток, чтобы обработать какую-то задачу, и этот скрипт выполняется при каждом запросе. Это означает, что для каждого запроса, ваше приложение будет создавать новый поток (это модель потоков 1:1 – один поток на один запрос). Если ваше приложение обслуживает 1тыс. запросов в секунду, это означает создание 1тыс. нитей в секунду! Наличие множества потоков, запущенных на одной машине, быстро наводнит ее, и проблема будет лишь усугубляться, т. к. скорость выполнения запроса будет увеличиваться.

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

После такого отступления, давайте сразу перейдём к делу!

Обработка разовых задач

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

Здесь метод run — это наша обработка, которая будет выполняться внутри нового потока. При вызове Thread::start , порождается новый поток и вызывается метод run . Затем мы присоединяем порождённый поток обратно в основной поток, вызвав Thread::join , который будет заблокирован до тех пор, пока порождённый поток не завершит своё выполнение. Это гарантирует, что задача завершит выполнение, прежде чем мы попытаемся вывести результат (который хранится в $task->response ).

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

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

Давайте взглянем на иерархию классов, предлагаемую расширением pthreads:

Мы уже рассмотрели и узнали основы классов Thread и Threaded , теперь давайте взглянем на остальные три ( Worker , Volatile , и Pool ).

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

Запуск нового потока для каждой задачи, которую нужно распараллелить, достаточно затратно. Это потому что архитектура «ничего-общего» должна быть реализована в pthreads, чтобы добиться многопоточности внутри PHP. Что означает, что весь контекст выполнения текущего экземпляра интерпретатора PHP (в том числе и каждый класс, интерфейс, трейт и функция) должна быть скопирована для каждого созданного потока. Поскольку это влечет за собой заметное влияние на производительность, поток всегда должен быть повторно использован, когда это возможно. Потоки могут быть переиспользованы двумя способами: с помощью Worker -ов или с помощью Pool -ов.

Класс Worker используется для выполнения ряда задач синхронно внутри другого потока. Это делается путем создания нового экземпляра Worker -а (который создает новый поток), а затем внесением задач в стек этого отдельного потока (с помощью Worker::stack ).

Вот небольшой пример:

В вышеприведённом примере в стек заносится 15 задач для нового объекта $worker через метод Worker::stack , а затем они обрабатываются в порядке их внесения. Метод Worker::collect , как показано выше, используется для очистки задач, как только они закончат выполнение. С его помощью внутри цикла while, мы блокируем основной поток, пока не будут завершены все задачи из стека и пока они не будут очищены — до того как мы вызовем Worker::shutdown . Завершение worker -а досрочно (т. е. пока есть еще задачи, которые должны быть выполнены) будет по-прежнему блокировать основной поток до тех пор, пока все задачи не завершат своё выполнение, просто задачи не будут почищены сборщиком мусора (что влечёт за собой утечки памяти).

Класс Worker предоставляет несколько других методов, относящихся к его стеку задач, включая Worker::unstack для удаления последней внесённой задачи и Worker::getStacked для получения количества задач в стеке выполнения. Стек worker -а содержит только задачи, которые должны быть выполнены. Как только задача из стека была выполнена, она удаляется и размещается в отдельном (внутреннем) стеке для сборки мусора (с помощью метода Worker::collect ).

Еще один способ переиспользовать поток при выполнении многих задач — это использование пула потоков (через класс Pool ). Пул потоков использует группу Worker -ов, чтобы дать возможность выполнять задачи одновременно, в котором фактор параллельности (число потоков пула, с которыми он работает) задается при создании пула.

Давайте адаптируем приведенный выше пример для использования пула worker -ов:

Есть несколько заметных различий при использовании пула, в отличие от воркера. Во-первых, пул не требует запуска вручную, он приступает к выполнению задач, как только они становятся доступными. Во-вторых, мы отправляем задачи в пул, а не укладываем их в стек. Кроме того, класс Pool не наследуется от Threaded , и поэтому он не может быть передан в другие потоки (в отличие от Worker ).

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

pthreads и (не)изменяемость

Последний класс, которого мы коснёмся, – Volatile , – новое дополнение к pthreads v3. Понятие неизменяемости стало важной концепцией в pthreads, так как без неё производительность существенно снижается. Поэтому по умолчанию, свойства Threaded -классов, которые сами являются Threaded -объектами, сейчас являются неизменными, и поэтому они не могут быть перезаписаны после их первоначального присвоения. Явная изменяемость для таких свойств сейчас пока предпочтительна, и все еще может быть достигнута с помощью нового класса Volatile .

Давайте взглянем на пример, который продемонстрирует новые ограничения неизменяемости:

Threaded -свойства у классов Volatile , с другой стороны, изменяемы:

Мы видим, что класс Volatile переопределяет неизменяемость, навязанную родительским классом Threaded , чтобы предоставить возможность изменять Threaded -свойства (а также unset() -ить).

Есть ещё один предмет обсуждения чтобы раскрыть тему изменяемости и класса Volatile – массивы. В pthreads массивы автоматически приводятся к Volatile -объектам при присвоении к свойству класса Threaded . Это потому что просто небезопасно манипулировать массивом из нескольких контекстов PHP.

Давайте снова взглянем на пример, чтобы лучше понимать некоторые вещи:

Мы видим, что Volatile -объекты могут быть обработаны так, как если бы они были массивами, т. к. они поддерживают операции с массивами, такие как (как показано выше) оператор подмножеств ( [] ). Однако, классы Volatile не поддерживают базовые функции с массивами, такие как array_pop и array_shift . Вместо этого, класс Threaded предоставляет нам подобные операции как встроенные методы.

В качестве демонстрации:

Другие поддерживаемые операции включают в себя Threaded::chunk и Threaded::merge .

Синхронизация

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

Для примера, давайте реализуем простейший счетчик:

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

Давайте исправим это так, что мы получим правильный вывод 20 , путем добавления синхронизации:

Синхронизированные блоки кода могут также взаимодействовать друг с другом, используя методы Threaded::wait и Threaded::notify (или Threaded::notifyAll ).

Вот поочерёдный инкремент в двух синхронизированных циклах while:

Вы можете заметить дополнительные условия, которые были размещены вокруг обращения к Threaded::wait . Эти условия имеют решающее значение, поскольку они позволяют синхронизированному колбэку возобновить работу, когда он получил уведомление и указанное условие равно true . Это важно, потому что уведомления могут поступать из других мест, кроме как при вызове Threaded::notify . Таким образом, если вызовы метода Threaded::wait не были заключены в условиях, мы будем выполнять ложные вызовы пробуждения, которые приведут к непредсказуемому поведению кода.

Заключение

Мы рассмотрели пять классов пакета pthreads ( Threaded , Thread , Worker , Volatile и Pool ), а также как каждый из классов используется. А ещё мы взглянули на новую концепцию неизменяемости в pthreads, сделали краткий обзор поддерживаемых возможностей синхронизации. С этими основами, мы можем теперь приступить к рассмотрению применения pthreads в случаях из реального мира! Это и будет темой нашего следующего поста.

Если вам интересен перевод следующего поста, дайте знать: комментируйте в соц. сетях, плюсуйте и делитесь постом с коллегами и друзьями.

Читать еще:  Php build query string
Ссылка на основную публикацию
Adblock
detector