Как статический код работает с несколькими потоками?

Обновление: Пожалуйста, взгляните на комментарии - этот ответ не соответствует вашему вопросу, но, возможно, он отвечает на другие вопросы пользователей, которые натолкнулись (я думаю, что из-за upvotes), поэтому я не буду удалять это " answer ":

Сначала: я знаю, что этот вопрос действительно устарел, но я искал именно эту проблему, и эта публикация была опубликована в Google # 1. Поэтому я реализовал версию docs.filter (принятый ответ), но, как я читал в mongoose v4.6.0 docs , мы теперь можем просто использовать:

Item.find({}).populate({
    path: 'tags',
    match: { tagName: { $in: ['funny', 'politics'] }}
}).exec((err, items) => {
  console.log(items.tags) 
  // contains only tags where tagName is 'funny' or 'politics'
})

Надеемся, что это поможет будущему пользователей поисковой системы.

13
задан Community 23 May 2017 в 12:00
поделиться

6 ответов

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

19
ответ дан 1 December 2019 в 19:30
поделиться

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

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

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

С уважением,
Оливер Ханаппи

2
ответ дан 1 December 2019 в 19:30
поделиться

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

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

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

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

1
ответ дан 1 December 2019 в 19:30
поделиться

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

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

Настройте поле ManualResetEvent, назовите его ActivateReader или что-то подобное, это станет более очевидным в дальнейшем. Инициализируйте его как false.

Установите логическое поле, назовите его TerminateReaderThread. Инициализируйте его как false, снова это станет более очевидным в дальнейшем.

Настройте поле Queue , назовите его Files и инициализируйте его.

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

Затем я настроил поток, который будет работать как читатель очереди. Этот поток ожидает срабатывания ManualResetEvent с помощью метода WaitAny () - это метод блокировки, который разблокируется после срабатывания ManualResetEvent. После отключения поток проверяет, не было ли инициировано завершение работы потока [путем проверки поля TerminateReaderThread].Если завершение работы было инициировано, поток завершает работу корректно, в противном случае он считывает следующий элемент из очереди и порождает рабочий поток для обработки файла. Затем я блокирую очередь, прежде чем проверять, остались ли какие-нибудь предметы. Если ничего не осталось, я сбрасываю событие ManualResetEvent, которое приостанавливает нашу цепочку при следующем обходе. Затем я разблокирую очередь, чтобы основной поток мог продолжать писать в нее.

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

Как только мое приложение решает, что поток чтения больше не нужен, оно устанавливает для поля TerminateReaderThread значение true. В следующий раз, когда поток читателя перейдет к началу своего процесса, будет активирован процесс его завершения.

2
ответ дан 1 December 2019 в 19:30
поделиться

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

8
ответ дан 1 December 2019 в 19:30
поделиться

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

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

3
ответ дан 1 December 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: