Многопоточность
Этот экспериментальный интерфейс поддерживает возможности многопоточности Julia. Типы и функции, описанные здесь, могут (и, вероятно, будут) изменены в будущем.
Base.Threads.threadidФункция
Threads.threadid()
Получить идентификатор текущей потока выполнения. У главного потока ID 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
Атомарно побитовое И 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
Атомарно побитовое 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.
Замки spin-lock типа «проверка-и-замена-и-проверка» самые быстрые до примерно 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.1.1/base/multi-threading/