Многопоточность
Этот экспериментальный интерфейс поддерживает возможности многопоточности Julia. Типы и функции, описанные здесь, могут (и, скорее всего, будут) изменены в будущем.
Base.Threads.threadidФункция
Threads.threadid()
Получить идентификатор текущей потока выполнения. Главный поток имеет идентификатор 1.
Base.Threads.nthreadsФункция
Threads.nthreads()
Получить количество потоков, доступных для процесса Julia. Это верхняя граница включительно для threadid().
Base.Threads.@threadsМакрос
Threads.@threads
Макрос для распараллеливания цикла for для выполнения с несколькими потоками. Он запускает nthreads() количество потоков, распределяет пространство итераций между ними и выполняет итерации параллельно. В конце цикла устанавливается барьер, который ждет завершения работы всех потоков, и цикл возвращается.
Base.Threads.@spawnМакрос
Threads.@spawn expr
Создать и запустить Task в любом доступном потоке. Для ожидания завершения задачи вызовите wait на результате этого макроса или вызовите fetch для ожидания и получения его возвращаемого значения.
Значения могут быть интерполированы в @spawn с помощью $, что копирует значение непосредственно в созданную базовую замыкание. Это позволяет вставлять значение переменной, изолируя асинхронный код от изменений значения переменной в текущей задаче.
Эта функция в настоящее время считается экспериментальной.
Этот макрос доступен начиная с Julia 1.3.
Интерполяция значений с помощью $ доступна начиная с Julia 1.4.
Base.Threads.AtomicТип
Threads.Atomic{T}
Содержит ссылку на объект типа T, гарантируя, что к нему обращаются атомарно, т.е. безопасным для потоков способом.
Только определенные "простые" типы могут использоваться атомарно, а именно примитивные типы boolean, integer и float-point. Это Bool, Int8...Int128, UInt8...UInt128, и Float16...Float64.
Новые атомарные объекты могут быть созданы из неатомарных значений; если не указано ничего, атомарный объект инициализируется нулём.
К атомарным объектам можно получить доступ, используя обозначение []:
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> x[] = 1
1
julia> x[]
1
Атомарные операции используют префикс atomic_, такой как atomic_add!, atomic_xchg! и т.д.
Base.Threads.atomic_cas!Функция
Threads.atomic_cas!(x::Atomic{T}, cmp::T, newval::T) where T
Атомарная операция сравнения и установки x
Атомарно сравнивает значение в x с cmp. Если они равны, записывает newval в x. В противном случае, оставляет x без изменений. Возвращает старое значение в x. Сравнивая возвращённое значение с cmp (через ===) можно узнать, было ли x изменено и теперь ли оно содержит новое значение newval.
Для получения дополнительных сведений см. инструкцию LLVM cmpxchg.
Эта функция может быть использована для реализации транзакционных семантик. Перед транзакцией записывает значение в x. После транзакции новое значение сохраняется только если x не был изменён в то время.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_cas!(x, 4, 2);
julia> x
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_cas!(x, 3, 2);
julia> x
Base.Threads.Atomic{Int64}(2)
исходный код
Base.Threads.atomic_xchg!Функция
Threads.atomic_xchg!(x::Atomic{T}, newval::T) where T
Атомарный обмен значением в x
Атомарно меняет значение в x на newval. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw xchg.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_xchg!(x, 2)
3
julia> x[]
2
исходный код
Base.Threads.atomic_add!Функция
Threads.atomic_add!(x::Atomic{T}, val::T) where T <: ArithmeticTypes
Атомарное сложение val к x
Выполняет x[] += val атомарно. Возвращает старое значение. Не определено для Atomic{Bool}.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw add.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_add!(x, 2)
3
julia> x[]
5
исходный код
Base.Threads.atomic_sub!Функция
Threads.atomic_sub!(x::Atomic{T}, val::T) where T <: ArithmeticTypes
Атомарное вычитание val из x
Выполняет x[] -= val атомарно. Возвращает старое значение. Не определено для Atomic{Bool}.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw sub.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_sub!(x, 2)
3
julia> x[]
1
исходный код
Base.Threads.atomic_and!Функция
Threads.atomic_and!(x::Atomic{T}, val::T) where T
Атомарное побитовое И x с val
Выполняет x[] &= val атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw and.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_and!(x, 2)
3
julia> x[]
2
исходный код
Base.Threads.atomic_nand!Функция
Threads.atomic_nand!(x::Atomic{T}, val::T) where T
Атомарное побитовое И-НЕ x с val
Выполняет x[] = ~(x[] & val) атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw nand.
Примеры
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
julia> Threads.atomic_nand!(x, 2)
3
julia> x[]
-3
исходный код
Base.Threads.atomic_or!Функция
Threads.atomic_or!(x::Atomic{T}, val::T) where T
Атомарное побитовое ИЛИ x с val
Выполняет x[] |= val атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw or.
Примеры
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
julia> Threads.atomic_or!(x, 7)
5
julia> x[]
7
исходный код
Base.Threads.atomic_xor!Функция
Threads.atomic_xor!(x::Atomic{T}, val::T) where T
Атомарное побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ x с val
Выполняет x[] $= val атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw xor.
Примеры
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
julia> Threads.atomic_xor!(x, 7)
5
julia> x[]
2
исходный код
Base.Threads.atomic_max!Функция
Threads.atomic_max!(x::Atomic{T}, val::T) where T
Атомарно сохраняет максимальное значение из x и val в x
Выполняет x[] = max(x[], val) атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw max.
Примеры
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
julia> Threads.atomic_max!(x, 7)
5
julia> x[]
7
исходный код
Base.Threads.atomic_min!Функция
Threads.atomic_min!(x::Atomic{T}, val::T) where T
Атомарно сохраняет минимальное значение из x и val в x
Выполняет x[] = min(x[], val) атомарно. Возвращает старое значение.
Для получения дополнительных сведений см. инструкцию LLVM atomicrmw min.
Примеры
julia> x = Threads.Atomic{Int}(7)
Base.Threads.Atomic{Int64}(7)
julia> Threads.atomic_min!(x, 5)
7
julia> x[]
5
исходный код
Base.Threads.atomic_fenceФункция
Threads.atomic_fence()
Вставка барьера последовательной согласованности
Вставляет барьер памяти с семантикой последовательной согласованности. В некоторых алгоритмах это необходимо, например, когда упорядочивание «захват/выпуск» недостаточно.
Вероятно, это очень дорогостоящая операция. Учитывая, что все атомные операции в Julia уже имеют семантику «захват/выпуск», явные барьеры в большинстве случаев не нужны.
Дополнительные сведения см. в инструкции LLVM fence
ccall с использованием пула потоков (Экспериментальная функция)
Base.@threadcallМакрос
@threadcall((cfunc, clib), rettype, (argtypes...), argvals...)
Макрос @threadcall вызывается так же, как ccall, но выполняет работу в другом потоке. Это полезно, когда нужно вызвать блокирующую функцию C, не заставляя основной julia поток блокироваться. Конкурентность ограничена размером пула потоков libuv, который по умолчанию составляет 4 потока, но может быть увеличен путем установки переменной среды UV_THREADPOOL_SIZE и перезапуска процесса julia
Обратите внимание, что вызываемая функция никогда не должна вызывать Julia.
исходный кодПримитивы низкоуровневой синхронизации
Эти строительные блоки используются для создания обычных объектов синхронизации.
Base.Threads.SpinLockТип
SpinLock()
Создает нерекурсивную блокировку вращения типа «проверка и проверка и установка». Рекурсивное использование приведет к тупику. Этот тип блокировки следует использовать только для кода, выполнение которого занимает мало времени и не приводит к блокировкам (например, при выполнении операций ввода-вывода). В общем случае следует использовать ReentrantLock.
Каждый lock должен быть сопоставлен с unlock.
Блокировки вращения «проверка и проверка и установка» наиболее эффективны при до 30 конкурирующих потоков. Если конкуренция выше, следует рассмотреть другие подходы к синхронизации.
исходный код
© 2009–2020 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.4.2/base/multi-threading/