Что такое thread safe

Что такое thread safe

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

Кроме того, если 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

Бинарники, собранные в потоко-небезопасном режиме (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.

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

Источник

Что такое потокобезопасность и как ее достичь?

Узнайте о различных вариантах использования потокобезопасности и параллельного доступа.

1. Обзор

Java поддерживает многопоточность из коробки. Это означает, что, выполняя байт-код одновременно в отдельных рабочих потоках, JVM способна повысить производительность приложения.

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

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

2. Реализации Без Состояния

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

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

Метод factorial() является детерминированной функцией без состояния. Учитывая конкретный вход, он всегда выдает один и тот же результат.

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

3. Неизменяемые Реализации

Неизменность-это мощная концепция, не зависящая от языка, и ее довольно легко достичь в Java.

Самый простой способ создать неизменяемый класс в Java-это объявить все поля private и final и не предоставлять установщики:

Объект Message Service фактически неизменяем, поскольку его состояние не может измениться после его построения. Следовательно, он потокобезопасен.

Более того, если MessageService действительно изменчив, но несколько потоков имеют к нему доступ только для чтения, он также потокобезопасен.

4. Локальные поля потока

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

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

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

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

В то время как другой может содержать массив из строк :

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

Аналогично, мы можем создавать локальные поля потока, назначая ThreadLocal экземплярам поля.

Рассмотрим, например, следующий класс StateHolder :

Мы можем легко сделать его локальной переменной потока следующим образом:

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

5. Синхронизированные коллекции

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

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

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

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

6. Параллельные Коллекции

В качестве альтернативы синхронизированным коллекциям мы можем использовать параллельные коллекции для создания потокобезопасных коллекций.

7. Атомные объекты

Чтобы понять проблему, которую это решает, давайте рассмотрим следующий класс Counter :

Теоретически конечное значение поля счетчик будет равно 2. Но мы просто не можем быть уверены в результате, потому что потоки выполняют один и тот же блок кода одновременно, и приращение не является атомарным.

Давайте создадим потокобезопасную реализацию класса Counter с помощью объекта AtomicInteger :

8. Синхронизированные методы

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

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

Мы можем создать потокобезопасную версию incrementCounter() другим способом, сделав ее синхронизированным методом:

Мы создали синхронизированный метод, добавив к сигнатуре метода префикс с ключевым словом synchronized.

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

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

Мы можем реализовать синхронизацию в методах экземпляра, статических методах и операторах (синхронизированные операторы).

9. Синхронизированные Заявления

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

Чтобы проиллюстрировать этот пример использования, давайте рефакторингуем метод incrementCounter() :

В отличие от методов synchronized, операторы synchronized должны указывать объект, обеспечивающий внутреннюю блокировку, обычно ссылку this.

9.1. Другие объекты в качестве замка

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

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

При использовании this для внутренней блокировки злоумышленник может вызвать взаимоблокировку, получив внутреннюю блокировку и запустив условие отказа в обслуживании (DoS).

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

9.2. Предостережения

Несмотря на то, что мы можем использовать любой объект Java в качестве встроенной блокировки, мы должны избегать использования Strings для целей блокировки:

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

10. Изменчивые Поля

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

Чтобы предотвратить эту ситуацию, мы можем использовать поля класса volatile:

Давайте рассмотрим следующий пример:

В этом случае каждый раз, когда JVM записывает переменную age | volatile в основную память, она также записывает переменную name в основную память. Это гарантирует, что последние значения обеих переменных хранятся в основной памяти, поэтому последующие обновления переменных будут автоматически видны другим потокам.

11. Реентерабельные Замки

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

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

Экземпляры ReentrantLock позволяют нам делать именно это, следовательно, предотвращая некоторые типы потоков в очереди от нехватки ресурсов :

Конструктор ReentrantLock принимает необязательный параметр fair |/boolean . Если установлено значение true , и несколько потоков пытаются получить блокировку, JVM отдаст приоритет самому длинному ожидающему потоку и предоставит доступ к блокировке .

12. Блокировка чтения/записи

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

Мы можем использовать ReadWriteLock lock следующим образом:

13. Заключение

Источник

What is thread safe or non-thread safe in PHP?

I saw different binaries for PHP, like non-thread or thread safe?

What does this mean?

What is the difference between these packages?

Что такое thread safe. Смотреть фото Что такое thread safe. Смотреть картинку Что такое thread safe. Картинка про Что такое thread safe. Фото Что такое thread safe

4 Answers 4

Needed background on concurrency approaches:

There are also other completely different concurrency models (using Asynchronous sockets and I/O), as well as ones that mix two or even three models together. For the purpose of answering this question, we are only concerned with the two models above, and taking Apache HTTP server as an example.

Needed background on how PHP «integrates» with web servers:

There are other methods for chaining PHP with Apache and other web servers, but mod_php is the most popular one and will also serve for answering your question.

You may not have needed to understand these details before, because hosting companies and GNU/Linux distros come with everything prepared for us.

Now, onto your question!

At this point, you should be thinking «OK, so if I’m using a multi-threaded web server and I’m going to embed PHP right into it, then I must use the thread-safe version of PHP». And this would be correct thinking. However, as it happens, PHP’s thread-safety is highly disputed. It’s a use-if-you-really-really-know-what-you-are-doing ground.

Final notes

In case you are wondering, my personal advice would be to not use PHP in a multi-threaded environment if you have the choice!

Источник

Уровень 27. Ответы на вопросы к собеседованию по теме уровня

Что такое дедлок?

Дедлок – это ситуация, когда два и более нитей заблокированы, ждущие друг друга. Дедлоком также называется взаимная блокировка.

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

Бывают взаимные блокировки порядка синхронизации (решаются назначением порядка);

Взаимная блокировка между объектами (различные объекты пытаются получить доступ к одним и тем же синхронизированным блокам);

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

Какие вы знаете стратегии, предотвращающие появление дедлоков?

Безусловно, если код написан без каких-либо ошибок, то взаимных блокировок в нем не будет. Но кто может поручиться, что его код написан без ошибок? Безусловно, тестирование помогает выявить значительную часть ошибок, но как мы уже видели ранее, ошибки в многопоточном коде нелегко диагностировать и даже после тестирования нельзя быть уверенным в отсутствии ситуаций взаимных блокировок. Можем ли мы как-то перестраховаться от блокировок? Ответ – да. Подобные техники применяются в движках баз данных, которым нередко необходимо восстанавливаться после взаимных блокировок (связанных с механизмом транзакций в БД). Интерфейс Lock и его реализации доступные в пакете java.util.concurrent.locks позволяют попытаться занять монитор, связанный с экземпляром данного класса методом tryLock (возвращает true, если удалось занять монитор).

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

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

The java.lang.Object.notify() wakes up a single thread that is waiting on this object’s monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object’s monitor by calling one of the wait methods.

This method should only be called by a thread that is the owner of this object’s monitor. A thread becomes the owner of the object’s monitor in one of three ways:

Only one thread at a time can own an object’s monitor.

The java.lang.Object.notifyAll() wakes up all threads that are waiting on this object’s monitor. A thread waits on an object’s monitor by calling one of the wait methods.

The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.

This method should only be called by a thread that is the owner of this object’s monitor.

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

Здесь отвечу просто цитатой из сайта: Синхронизация потоков

Зачем это надо. Дело в том, что notify может вызвать кто угодно. Просто по ошибке, от которой никто не застрахован. В том случае из опыта, о котором я рассказывал выше, мы взялись за переделку именно для того, чтобы избежать такой возможности. Просто спрятали объект, на котором происходит синхронизация. И доступ к нему имел только наш код. Это хорошая практика, но не всегда возможно, к сожалению. Так вот, если поток ждет выполнения некоторого условия – вариант с while надежнее. Если поток пустили по ошибке – он опять проверит условие и, если надо, будет ждать дальше.

The java.lang.Object.notifyAll() wakes up all threads that are waiting on this object’s monitor. A thread waits on an object’s monitor by calling one of the wait methods.

Пробуждает все нити, которые ждали на этом мониторе.

Immutable объект — это объект, состояние которого после создания невозможно изменить. В случае Java это значит что все поля экземпляра у класс отмечены как final и являются примитивами или тоже immutable типами.

После создания экземпляра ImmutablePoint его модификация невозможна.

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

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

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

Что такое «thread-safe»?

Thread safe means that a method or class instance can be used by multiple threads at the same time without any problems occuring.

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

Consider the following method:

Now thread A and thread B both would like to execute AddOne(). but A starts first and reads the value of myInt (0) into tmp. Now for some reason the scheduler decides to halt thread A and defer execution to thread B. Thread B now also reads the value of myInt (still 0) into it’s own variable tmp. Thread B finishes the entire method, so in the end myInt = 1. And 1 is returned. Now it’s Thread A’s turn again. Thread A continues. And adds 1 to tmp (tmp was 0 for thread A). And then saves this value in myInt. myInt is again 1.

So in this case the method AddOne was called two times, but because the method was not implemented in a thread safe way the value of myInt is not 2, as expected, but 1 because the second thread read the variable myInt before the first thread finished updating it.

Так что в этом случае метод AddOne был вызван два раза, но так как этот метод не был реализован в потоке безопасным способом величина myInt не 2, как ожидалось, а 1, потому что второй поток чтения переменной myInt закончился перед первой нитью до его обновления.

Creating thread safe methods is very hard in non trivial cases. And there are quite a few techniques. In Java you can mark a method as synchronized, this means that only one thread can execute that method at a given time. The other threads wait in line. This makes a method thread safe, but if there is a lot of work to be done in a method, then this wastes a lot of time. Another technique is to ‘mark only a small part of a method as synchronized’ by creating a lock or semaphore, and locking this small part (usually called the critical section). There are even some methods that are implemented as lockless thread safe, which means that they are built in such a way that multiple threads can race through them at the same time without ever causing problems, this can be the case when a method only executes one atomic call. Atomic calls are calls that can’t be interrupted and can only be done by one thread at a time.

Создание потоко-безопасных методов очень трудно. В Java вы можете пометить метод как синхронизированный, это будет означать, что только один поток может выполнить этот метод в данный момент времени. Другие нити, будут ждать в очереди. Это делает метод потоко-безопасным, но если много работы предстоит сделать в методе, то на это будет уходить много времени. Другой метод заключается в разметке лишь малой части метода, как синхронизированного ‘путем создания локов(locks) или семафоров, и запирании этой небольшой части (обычно называемый критический раздел (critical section)). Есть даже некоторые методы, которые реализуются как беззамочные потокобезопасные (lockless thread safe), это означает, что они построены таким образом, что несколько потоков могут проходить через них в одно время и никогда не вызывают проблем, это может быть в случае, когда метод выполняет только один атомарный вызов. Атомарные вызовы это вызовы, которые не могут быть прерваны, и может быть реализованы только одним потоком.

Что такое «happens-before»?

Есть статья на википедии, она не конкретно про «happens-before», но все – таки.

В частности, одно выполняется прежде другого для таких операций (список не исчерпывающий):

Что такое JMM?

И вот выдержка из нее:

A memory model describes, given a program and an execution trace of that program, whether the execution trace is a legal execution of the program. The Java programming language memory model works by examining each read in an execution trace and checking that the write observed by that read is valid according to certain rules.

Я понял на своем уровне что это набор правил:

Правило № 1: однопоточные программы исполняются псевдопоследовательно. Это значит: в реальности процессор может выполнять несколько операций за такт, заодно изменив их порядок, однако все зависимости по данным остаются, так что поведение не отличается от последовательного. Правило № 2: нет невесть откуда взявшихся значений. Чтение любой переменной (кроме не-volatile long и double, для которых это правило может не выполняться) выдаст либо значение по умолчанию (ноль), либо что-то, записанное туда другой командой.br /> И правило № 3: остальные события выполняются по порядку, если связаны отношением строгого частичного порядка «выполняется прежде» (англ. happens before).

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *