Многопоточность
Этот экспериментальный интерфейс поддерживает возможности многопоточности Julia. Типы и функции, описанные здесь, могут (и, вероятно, будут) изменяться в будущем.
Base.Threads.threadidФункция
Threads.threadid()
Получить идентификатор текущей потоковой нити выполнения. У главного потока идентификатор 1.
Base.Threads.nthreadsФункция
Threads.nthreads()
Получить количество потоков, доступных для процесса Julia. Это верхняя граница (включительно) для threadid().
Base.Threads.@threadsМакрос
Threads.@threads
Макрос для распараллеливания цикла for для выполнения с несколькими потоками. Это создаёт nthreads() количество потоков, распределяет область итераций между ними и выполняет итерации параллельно. В конце цикла размещается барьер, который ожидает завершения выполнения всех потоков, и цикл возвращает результат.
Base.Threads.AtomicТип
Threads.Atomic{T}
Хранит ссылку на объект типа T, гарантируя, что к нему обращаются атомарно, т.е. безопасным для многопоточности способом.
Только определённые "простые" типы могут использоваться атомарно, а именно примитивные булевы, целые и вещественные типы. Это 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
Атомарно выполняет побитовую операцию AND 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
Атомарно выполняет побитовую операцию NAND (не-и) 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
Атомарно выполняет побитовую операцию OR 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
Атомарно выполняет побитовую операцию XOR (исключающее ИЛИ) 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.AbstractLockТип
AbstractLock
Абстрактный супертип, описывающий типы, которые реализуют потокобезопасные синхронизационные примитивы: lock, trylock, unlock и islocked.
Base.lockФункция
lock(lock)
Получить lock при его доступности. Если блокировка уже заблокирована другой задачей/потоком, подождите, пока она не станет доступной.
Каждый lock должен быть сопоставлен с unlock.
Base.unlockФункция
unlock(lock)
Освобождает владение lock.
Если это рекурсивная блокировка, которая уже была получена ранее, уменьшите внутренний счётчик и верните результат немедленно.
исходный код
Base.trylockФункция
trylock(lock) -> Success (Boolean)
Получить блокировку, если она доступна, и вернуть true в случае успеха. Если блокировка уже заблокирована другой задачей/потоком, вернуть false.
Каждый успешный trylock должен быть сопоставлен с unlock.
Base.islockedФункция
islocked(lock) -> Status (Boolean)
Проверить, удерживается ли lock любой задачей/потоком. Это не следует использовать для синхронизации (см. вместо этого trylock).
Base.ReentrantLockТип
ReentrantLock()
Создаёт рекурсивную блокировку для синхронизации Taskов. Одна и та же задача может получать блокировку любое количество раз. Каждый lock должен быть сопоставлен с unlock.
Эта блокировка НЕ потокобезопасна. См. Threads.Mutex для потокобезопасной блокировки.
Base.Threads.MutexТип
Mutex()
Это стандартные системные мьютексы для блокировки критических участков кода.
В Windows это объект критической секции, в pthreads это pthread_mutex_t.
См. также SpinLock для более лёгкой блокировки.
Base.Threads.SpinLockТип
SpinLock()
Создаёт нерекурсивную блокировку. Рекурсивное использование приведёт к тупиковой ситуации. Каждый lock должен быть сопоставлен с unlock.
Блокировки типа «проверить и установить» работают быстрее до примерно 30-ти конкурирующих потоков. Если у вас больше конкуренции, возможно, блокировка — не лучший способ синхронизации.
См. также RecursiveSpinLock для версии, допускающей рекурсию.
См. также Mutex для более эффективной версии на одном ядре или если блокировка может удерживаться в течение значительного времени.
Base.Threads.RecursiveSpinLockТип
RecursiveSpinLock()
Создаёт рекурсивную блокировку. Один и тот же поток может получить блокировку любое количество раз. Каждый lock должен быть сопоставлен с unlock.
См. также SpinLock для немного более быстрой версии.
См. также Mutex для более эффективной версии на одном ядре или если блокировка может удерживаться в течение значительного времени.
Base.SemaphoreТип
Semaphore(sem_size)
Создаёт счётчик семафоров, который позволяет максимум sem_size получения в использовании в любой момент. Каждое получение должно быть сопоставлено с освобождением.
Данная конструкция НЕ потокобезопасна.
исходный код
Base.acquireФункция
acquire(s::Semaphore)
Подождите, пока один из sem_size разрешений станет доступным, блокируясь, пока одно не будет получено.
Base.releaseФункция
release(s::Semaphore)
Возвращает одно разрешение в пул, возможно, позволяя другой задаче получить его и возобновить выполнение.
исходный код
© 2009–2019 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.0.4/base/multi-threading/