AnyMath 文档

多线程

Threads.@threads [schedule] for ... end

一个宏来执行一个 循环并联。 迭代空间分配给粗粒度任务。 此策略可由 时间表 争论。 循环的执行等待所有迭代的评估。

产生的任务 @线程 计划于 :默认值 线程池。 这意味着 @线程 不会使用线程从 :互动 threadpool,即使从主线程或交互池中的任务调用。 该 :默认值 threadpool用于计算密集型并行工作负载。

请参阅: @产卵pmap分发的. 有关threadpools的更多信息,请参阅以下章节 threadpools

*扩展帮助*

*语义*

除非调度选项指定了更强的保证,否则由 @线程 宏具有以下语义。

@线程 宏以未指定的顺序并可能并发地执行循环体。 它不指定任务和工作线程的确切分配。 每个执行的分配可以是不同的。 循环体代码(包括从其传递调用的任何代码)不得对迭代到任务或执行它们的工作线程的分布做出任何假设。 每次迭代的循环体必须能够独立于其他迭代向前推进,并且不受数据竞争的影响。 因此,迭代之间的无效同步可能会死锁,而不同步的内存访问可能会导致未定义的行为。

例如,上述条件暗示:

*在迭代中获取的锁_must_将在同一迭代中释放。 *使用阻塞基元在迭代之间进行通信,如 频道s是不正确的。 *仅写入不跨迭代共享的位置(除非使用锁或原子操作)。 *除非 :静态 使用schedule,其值为 线程()即使在一次迭代中也可能发生变化。 见 任务迁移.

*调度员*

没有scheduler参数,确切的调度是未指定的,并且在Julia版本中有所不同。 目前, :动态 未指定调度程序时使用。

兼容性

朱莉娅1.5 时间表 自Julia1.5起,参数可用。

*`:动态` (默认)*

:动态 scheduler对可用的工作线程动态执行迭代。 当前的实现假设每个迭代的工作量是一致的。 但是,这种假设可能会在未来被删除。

此调度选项只是对底层执行机制的提示。 然而,可以预期一些属性。 的数量 任务s使用的 :动态 scheduler以可用工作线程数的小常数倍数为界(线程。线程大小()). 每个任务处理迭代空间的连续区域。 因此, @threads:x中的动态x;f(x);end 通常比 @sync for x in xs;@spawn f(x);end 如果 长度(x) 显着大于工作线程的数量和 f(x) 相对小于生成和同步任务的成本(通常小于10微秒)。

兼容性

朱莉娅1.8 :动态 选择 时间表 参数是可用的,默认为朱莉娅1.8.

*`:贪婪`*

:贪婪 调度程序生成到 线程。线程大小()任务,每个任务在生成给定的迭代值时贪婪地工作。 一旦一个任务完成其工作,它就会从迭代器中获取下一个值。 由任何单个任务完成的工作不一定是来自迭代器的连续值。 给定的迭代器可能会永远产生值,只需要迭代器接口(没有索引)。

如果单个迭代的工作负载不均匀/分布较大,则此调度选项通常是一个不错的选择。

兼容性

朱莉娅1.11 :贪婪 选择 时间表 自Julia1.11起,参数可用。

*`:静态`*

:静态 scheduler为每个线程创建一个任务,并在它们之间平均分配迭代,将每个任务专门分配给每个线程。 特别是,价值 线程()保证在一次迭代内是恒定的。 指定 :静态 是一个错误,如果从另一个内部使用 @线程 循环或从1以外的线程。

:静态 调度是为了支持在Julia1.3之前编写的代码的转换而存在的。 在新编写的库函数中, :静态 不鼓励进行调度,因为不能从任意工作线程调用使用此选项的函数。

*例子*

为了说明不同的调度策略,请考虑以下函数 n.忙碌的,忙碌的 包含运行给定秒数的非屈服定时循环。

julia> function busywait(seconds)
            tstart = time_ns()
            while (time_ns() - tstart) / 1e9 < seconds
            end
        end

julia> @time begin
            Threads.@spawn busywait(5)
            Threads.@threads :static for i in 1:Threads.threadpoolsize()
                busywait(1)
            end
        end
6.003001 seconds (16.33 k allocations: 899.255 KiB, 0.25% compilation time)

julia> @time begin
            Threads.@spawn busywait(5)
            Threads.@threads :dynamic for i in 1:Threads.threadpoolsize()
                busywait(1)
            end
        end
2.012056 seconds (16.05 k allocations: 883.919 KiB, 0.66% compilation time)

:动态 示例需要2秒,因为其中一个非占用线程能够运行两个1秒迭代来完成for循环。

Threads.foreach(f, channel::Channel;
                schedule::Threads.AbstractSchedule=Threads.FairSchedule(),
                ntasks=Threads.threadpoolsize())

类似于 foreach(f,通道),但迭代结束 频道 并呼吁 f 被分割开来 ntasks的 产生的任务 线程。@产卵. 此函数将等待所有内部生成的任务完成后再返回。

如果 时间表isa FairSchedule, 线程。n.前,前 将尝试以使Julia的调度程序能够更自由地跨线程负载平衡工作项的方式生成任务。 这种方法通常具有更高的每项开销,但可能比 [医]静力学 与其他多线程工作负载并行。

如果 时间表isa StaticSchedule, 线程。n.前,前 将以比每个项目开销更低的方式生成任务 [医]公平合理,但不太适合负载平衡。 因此,这种方法可能更适合细粒度,统一的工作负载,但可能比 [医]公平合理 与其他多线程工作负载并行。

*例子*

julia> n = 20

julia> c = Channel{Int}(ch -> foreach(i -> put!(ch, i), 1:n), 1)

julia> d = Channel{Int}(n) do ch
           f = i -> put!(ch, i^2)
           Threads.foreach(f, c)
       end

julia> collect(d)
collect(d) = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400]
兼容性

Julia1.6此功能需要Julia1.6或更高版本。

Threads.@spawn [:default|:interactive|:samepool] expr

创建一个 任务时间表它要在指定threadpool中的任何可用线程上运行: :默认值, :互动,或 :samepool 以使用与调用者相同的。 :默认值 如果未指定,则使用。 一旦一个线程可用,任务就被分配给一个线程。 要等待任务完成,请致电 等等!对此宏的结果,或调用 取货/取货来等待,然后获取其返回值。

值可以插值成 @产卵$,它将值直接复制到构造的底层闭包中。 这允许您插入变量的_value_,将异步代码与当前任务中变量值的更改隔离开来。

请注意,如果任务产生,任务运行的线程可能会发生变化,因此 线程() 不应被视为任务的常量。 见 任务迁移,而更广泛 多线程手册进一步重要的注意事项。 另见关于 threadpools

兼容性

Julia1.3此宏从Julia1.3开始可用。

兼容性

Julia1.4通过内插值 $ 从Julia1.4开始可用。

兼容性

Julia1.9一个threadpool可以指定为Julia1.9。

兼容性

Julia1.12可以指定与Julia1.12相同的线程池。

*例子*

julia> t() = println("Hello from ", Threads.threadid());

julia> tasks = fetch.([Threads.@spawn t() for i in 1:4]);
Hello from 1
Hello from 1
Hello from 3
Hello from 4
Threads.threadid([t::Task]) -> Int

获取当前执行线程的ID号,或者任务的线程 t. 主线程有ID 1.

*例子*

julia> Threads.threadid()
1

julia> Threads.@threads for i in 1:4
          println(Threads.threadid())
       end
4
2
5
4

julia> Threads.threadid(Threads.@spawn "foo")
2

请注意,如果任务产生,则任务运行的线程可能会更改,这称为 任务迁移. 出于这个原因,在大多数情况下,它是不安全的使用 threadid([任务]) 索引到缓冲区或有状态对象的向量中。

Threads.maxthreadid() -> Int

使用原子获取语义,获取Julia进程可用的线程数(跨所有线程池)的下限。 结果将始终大于或等于 线程()以及 threadid(任务) 对于任何任务,你可以在调用之前观察 最大线程.

Threads.nthreads(:default | :interactive) -> Int

获取指定线程池内的当前线程数。 线程在 :互动 有身份证号码 1:nthreads(:interactive),而线程在 :默认值 有身分证号码 nthreads(:interactive)。+(1:nthreads(:默认)).

请参阅 布拉斯。get_num_线程布拉斯。set_num_threads线性代数标准库,以及 nprocs()分发的标准图书馆及 线程。最大线程().

Threads.threadpool(tid = threadid()) -> Symbol

返回指定线程的threadpool; :默认值, :互动,或 :外国.

Threads.nthreadpools() -> Int

返回当前配置的线程池数。

Threads.threadpoolsize(pool::Symbol = :default) -> Int

获取默认线程池(或指定线程池)可用的线程数。

请参阅: 布拉斯。get_num_线程布拉斯。set_num_threads线性代数标准库,以及 nprocs()分发的标准库。

Threads.ngcthreads() -> Int

返回当前配置的GC线程数。 这包括标记线程和并发扫描线程。

请参阅 多线程

原子操作

不安全指针操作与加载和存储声明为 [医]原子std::原子 c11及C型++分别为23. 如果不支持以原子方式加载Julia类型,则可能会引发错误 T.

@atomic var
@atomic order ex

马克 瓦尔 作为原子执行,如果 是受支持的表达式。 如果没有 秩序 指定它默认为:sequentially_consistent。

@atomic a.b.x = new
@atomic a.b.x += addend
@atomic :release a.b.x = new
@atomic :acquire_release a.b.x += addend
@atomic m[idx] = new
@atomic m[idx] += addend
@atomic :release m[idx] = new
@atomic :acquire_release m[idx] += addend

以原子方式执行右侧表示的存储操作并返回新值。

带赋值(=),此操作转换为一个 setproperty!(a.b,:x,新) 或者,在引用的情况下,一个 setindex_atomic!(m,订单,新,idx) 呼叫,与 秩序 拖欠 :sequentially_consistent.

对于任何修改运算符,此操作转换为 modifyproperty!(a.b,:x,op,addend)[2] 或者,在引用的情况下,一个 modifyindex_atomic!(m,订单,op,addend,idx。..)[2] 呼叫,与 秩序 违约 :sequentially_consistent.

@atomic a.b.x max arg2
@atomic a.b.x + arg2
@atomic max(a.b.x, arg2)
@atomic :acquire_release max(a.b.x, arg2)
@atomic :acquire_release a.b.x + arg2
@atomic :acquire_release a.b.x max arg2
@atomic m[idx] max arg2
@atomic m[idx] + arg2
@atomic max(m[idx], arg2)
@atomic :acquire_release max(m[idx], arg2)
@atomic :acquire_release m[idx] + arg2
@atomic :acquire_release m[idx] max arg2

原子地执行右侧表示的二进制操作。 将结果存储到第一个参数中的字段或引用中,并返回值 (新旧).

此操作转换为 modifyproperty!(a.b,:x,func,arg2) 或者,在引用的情况下, modifyindex_atomic!(m,订单,func,arg2,idx) 呼叫,与 秩序 违约 :sequentially_consistent.

每场原子部分了解更多细节.

*例子*

julia> mutable struct Atomic{T}; @atomic x::T; end

julia> a = Atomic(1)
Atomic{Int64}(1)

julia> @atomic a.x # fetch field x of a, with sequential consistency
1

julia> @atomic :sequentially_consistent a.x = 2 # set field x of a, with sequential consistency
2

julia> @atomic a.x += 1 # increment field x of a, with sequential consistency
3

julia>@atomic a.x+1#a的递增字段x,具有顺序一致性
3 => 4

julia>@atomic a.x#获取a的字段x,具有顺序一致性
4

julia>@atomic max(a.x,10)#将a的字段x更改为最大值,具有顺序一致性
4 => 10

julia>@atomic a.x max5#再次将a的字段x更改为最大值,具有顺序一致性
10 => 10
julia> mem = AtomicMemory{Int}(undef, 2);

julia> @atomic mem[1] = 2 # set mem[1] to value 2 with sequential consistency
2

julia> @atomic :monotonic mem[1] # fetch the first value of mem, with monotonic consistency
2

julia> @atomic mem[1] += 1 # increment the first value of mem, with sequential consistency
3

julia> @atomic mem[1] + 1 # increment the first value of mem, with sequential consistency
3 => 4

julia> @atomic mem[1] # fetch the first value of mem, with sequential consistency
4

julia> @atomic max(mem[1], 10) # change the first value of mem to the max value, with sequential consistency
4 => 10

julia> @atomic mem[1] max 5 # again change the first value of mem to the max value, with sequential consistency
10 => 10
兼容性

Julia1.7原子字段功能至少需要Julia1.7。

兼容性

Julia1.12原子引用功能至少需要Julia1.12。

@atomicswap a.b.x = new
@atomicswap :sequentially_consistent a.b.x = new
@atomicswap m[idx] = new
@atomicswap :sequentially_consistent m[idx] = new

商店 新的 进入 a.b.x (m[idx] 在引用的情况下)并返回旧值 a.b.x (存储在的旧值 m[idx],分别)。

此操作转换为 swapproperty!(a.b,:x,新) 或者,在参考的情况下, swapindex_atomic!(mem,订单,新,idx) 呼叫,与 秩序 拖欠 :sequentially_consistent.

每场原子部分了解更多细节.

*例子*

julia> mutable struct Atomic{T}; @atomic x::T; end

julia> a = Atomic(1)
Atomic{Int64}(1)

julia> @atomicswap a.x = 2+2 # replace field x of a with 4, with sequential consistency
1

julia> @atomic a.x # fetch field x of a, with sequential consistency
4
julia> mem = AtomicMemory{Int}(undef, 2);

julia> @atomic mem[1] = 1;

julia> @atomicswap mem[1] = 4 # replace the first value of `mem` with 4, with sequential consistency
1

julia> @atomic mem[1] # fetch the first value of mem, with sequential consistency
4
兼容性

Julia1.7原子字段功能至少需要Julia1.7。

兼容性

Julia1.12原子引用功能至少需要Julia1.12。

@atomicreplace a.b.x expected => desired
@atomicreplace :sequentially_consistent a.b.x expected => desired
@atomicreplace :sequentially_consistent :monotonic a.b.x expected => desired
@atomicreplace m[idx] expected => desired
@atomicreplace :sequentially_consistent m[idx] expected => desired
@atomicreplace :sequentially_consistent :monotonic m[idx] expected => desired

以原子方式执行该对表示的条件替换,返回值 (老,成功::Bool). 哪里 成功 指示替换是否已完成。

此操作转换为 更换产品!(a.b,:x,期望的,期望的) 或者,在引用的情况下,一个 replaceindex_atomic!(mem,success_order,fail_order,expected,desired,idx) 打电话,两个命令都默认 :sequentially_consistent.

每场原子部分了解更多细节.

*例子*

julia> mutable struct Atomic{T}; @atomic x::T; end

julia> a = Atomic(1)
Atomic{Int64}(1)

julia> @atomicreplace a.x 1 => 2 # replace field x of a with 2 if it was 1, with sequential consistency
(old = 1, success = true)

julia> @atomic a.x # fetch field x of a, with sequential consistency
2

julia> @atomicreplace a.x 1 => 3 # replace field x of a with 2 if it was 1, with sequential consistency
(old = 2, success = false)

julia> xchg = 2 => 0; # replace field x of a with 0 if it was 2, with sequential consistency

julia> @atomicreplace a.x xchg
(old = 2, success = true)

julia> @atomic a.x # fetch field x of a, with sequential consistency
0
julia> mem = AtomicMemory{Int}(undef, 2);

julia> @atomic mem[1] = 1;

julia> @atomicreplace mem[1] 1 => 2 # replace the first value of mem with 2 if it was 1, with sequential consistency
(old = 1, success = true)

julia> @atomic mem[1] # fetch the first value of mem, with sequential consistency
2

julia> @atomicreplace mem[1] 1 => 3 # replace field x of a with 2 if it was 1, with sequential consistency
(old = 2, success = false)

julia> xchg = 2 => 0; # replace field x of a with 0 if it was 2, with sequential consistency

julia> @atomicreplace mem[1] xchg
(old = 2, success = true)

julia> @atomic mem[1] # fetch the first value of mem, with sequential consistency
0
兼容性

Julia1.7原子字段功能至少需要Julia1.7。

兼容性

Julia1.12原子引用功能至少需要Julia1.12。

@atomiconce a.b.x = value
@atomiconce :sequentially_consistent a.b.x = value
@atomiconce :sequentially_consistent :monotonic a.b.x = value
@atomiconce m[idx] = value
@atomiconce :sequentially_consistent m[idx] = value
@atomiconce :sequentially_consistent :monotonic m[idx] = value

如果以前未设置值,则以原子方式执行值的条件赋值。 返回值 成功::Bool 指示分配是否已完成。

此操作转换为 setpropertyonce!(a.b,:x,值) 或者,在引用的情况下,一个 setindexonce_atomic!(m,success_order,fail_order,value,idx) 打电话,两个命令都默认 :sequentially_consistent.

每场原子部分了解更多细节.

*例子*

julia> mutable struct AtomicOnce
           @atomic x
           AtomicOnce() = new()
       end

julia> a = AtomicOnce()
AtomicOnce(#undef)

julia> @atomiconce a.x = 1 # set field x of a to 1, if unset, with sequential consistency
true

julia> @atomic a.x # fetch field x of a, with sequential consistency
1

julia> @atomiconce :monotonic a.x = 2 # set field x of a to 1, if unset, with monotonic consistence
false
julia> mem = AtomicMemory{Vector{Int}}(undef, 1);

julia> isassigned(mem, 1)
false

julia> @atomiconce mem[1] = [1] # set the first value of mem to [1], if unset, with sequential consistency
true

julia> isassigned(mem, 1)
true

julia> @atomic mem[1] # fetch the first value of mem, with sequential consistency
1-element Vector{Int64}:
 1

julia> @atomiconce :monotonic mem[1] = [2] # set the first value of mem to [2], if unset, with monotonic
false

julia> @atomic mem[1]
1-element Vector{Int64}:
 1
兼容性

Julia1.11原子字段功能至少需要Julia1.11。

兼容性

Julia1.12原子引用功能至少需要Julia1.12。

AtomicMemory{T} == GenericMemory{:atomic, T, Core.CPU}

固定尺寸 DenseVector{T}. 获取它的任何单个元素都是原子地执行的( :单调 默认情况下订购)。

警告访问 原子记忆 必须使用 @原子宏或较低级别的接口函数: 基地。getindex_原子, 基地。setindex_atomic!, 基地。setindexonce_atomic!, 基地。swapindex_atomic!, 基地。modifyindex_atomic!,而 基地。replaceindex_atomic!.

有关详细信息,请参阅 原子操作以及宏 @原子, @atomiconce, @atomicswap,和 @atomicreplace.

兼容性

Julia1.11这种类型需要Julia1.11或更高版本。

兼容性

Julia1.12较低级别的接口函数或 @原子 macro需要Julia1.12或更高版本。

还有可选的内存排序参数 不安全 选择C/C的函数集++-这些原子操作的兼容版本,如果该参数指定为 卸载/卸载, unsafe_store!, unsafe_swap!, unsafe_replace!,和 unsafe_modify!.

警告以下Api已被弃用,但可能会在多个版本中保持对它们的支持。

Threads.Atomic{T}

保存对类型对象的引用 T,确保它仅以原子方式访问,即以线程安全的方式访问。

只有某些"简单"类型可以原子地使用,即基元布尔型、整数型和浮点型。 这些是 布尔, Int8…​Int128, UInt8…​UInt128,而 漂浮物16…​漂浮64.

可以从非原子值创建新的原子对象;如果没有指定,则原子对象初始化为零。

原子对象可以使用 [] 符号:

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

julia> x[] = 1
1

julia> x[]
1

原子操作使用 原子_ 前缀,如 atomic_add!, atomic_xchg!等。

Threads.atomic_cas!(x::Atomic{T}, cmp::T, newval::T) where T

原子比较和设置 x

原子地比较值在 xcmp技术. 如果相等,写 新瓦尔x. 否则,叶子 x 未修改。 返回旧值in x. 通过将返回的值与 cmp技术 (通过 === 人们知道是否 x 被修改,现在持有新的值 新瓦尔.

有关详细信息,请参阅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)
Threads.atomic_xchg!(x::Atomic{T}, newval::T) where T

原子地交换价值 x

原子地交换价值 x新瓦尔. 返回*old*值。

有关更多详细信息,请参阅LLVM的 atomicrmwxchg 指示。

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

julia> Threads.atomic_xchg!(x, 2)
3

朱莉娅>x[]
2
Threads.atomic_add!(x::Atomic{T}, val::T) where T <: ArithmeticTypes

原子添加 瓦尔x

表演/表演 x[]+=val 原子上。 返回*old*值。 未定义为 原子{Bool}.

有关详细信息,请参阅LLVM的 atomicrmw添加 指示。

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

julia> Threads.atomic_add!(x, 2)
3

julia> x[]
5
Threads.atomic_sub!(x::Atomic{T}, val::T) where T <: ArithmeticTypes

原子地减去 瓦尔x

表演/表演 x[]-=val 原子上。 返回*old*值。 未定义为 原子{Bool}.

有关详细信息,请参阅LLVM的 atomicrmw子 指示。

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

julia> Threads.atomic_sub!(x, 2)
3

julia> x[]
1
Threads.atomic_and!(x::Atomic{T}, val::T) where T

原子按位-和 x瓦尔

表演/表演 x[]&=val 原子上。 返回*old*值。

有关详细信息,请参阅LLVM的 atomicrmw和 指示。

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

朱莉娅>线程。atomic_and!(x,2)
3

朱莉娅>x[]
2
Threads.atomic_nand!(x::Atomic{T}, val::T) where T

原子按位与非(非和) x瓦尔

表演/表演 x[]=~(x[]&val) 原子上。 返回*old*值。

有关更多详细信息,请参阅LLVM的 n.原子,原子 指示。

*例子*

julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)

julia> Threads.atomic_nand!(x, 2)
3

julia> x[]
-3
Threads.atomic_or!(x::Atomic{T}, val::T) where T

原子按位-或 x瓦尔

表演/表演 x[]/=val 原子上。 返回*old*值。

有关更多详细信息,请参阅LLVM的 atomicrmw或 指示。

*例子*

julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)

julia> Threads.atomic_or!(x, 7)
5

julia> x[]
7
Threads.atomic_xor!(x::Atomic{T}, val::T) where T

Atomically bitwise-xor(exclusive-or) x瓦尔

表演/表演 x[]△=val 原子上。 返回*old*值。

有关更多详细信息,请参阅LLVM的 atomicrmw异或 指示。

*例子*

julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)

julia> Threads.atomic_xor!(x, 7)
5

julia> x[]
2
Threads.atomic_max!(x::Atomic{T}, val::T) where T

原子地存储最大的 x瓦尔x

表演/表演 x[]=max(x[],val) 原子上。 返回*old*值。

有关详细信息,请参阅LLVM的 atomicrmw最大 指示。

*例子*

julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)

julia> Threads.atomic_max!(x, 7)
5

julia> x[]
7
Threads.atomic_min!(x::Atomic{T}, val::T) where T

原子地存储最小 x瓦尔x

表演/表演 x[]=min(x[],val) 原子上。 返回*old*值。

有关详细信息,请参阅LLVM的 atomicrmw分钟 指示。

*例子*

julia> x = Threads.Atomic{Int}(7)
Base.Threads.Atomic{Int64}(7)

julia> Threads.atomic_min!(x, 5)
7

julia> x[]
5
Threads.atomic_fence()

插入顺序一致性内存围栏

插入具有顺序一致的排序语义的内存围栏。 有些算法需要这样做,即在获取/释放顺序不足的情况下。

这可能是一个非常昂贵的操作。 鉴于Julia中的所有其他原子操作已经具有acquire/release语义,在大多数情况下不应该需要显式围栏。

有关详细信息,请参阅LLVM的 栅栏 指示。

使用libuv线程池的ccall(实验)

@threadcall((cfunc, clib), rettype, (argtypes...), argvals...)

@threadcall 宏的调用方式与 ccall但是在不同的线程中工作。 当您想要调用阻塞C函数而不导致当前时,这很有用 朱莉娅 线程成为阻塞。 并发性受到libuv线程池大小的限制,该线程池默认为4个线程,但可以通过设置 UV_THREADPOOL_SIZE 环境变量并重新启动 朱莉娅 过程。

请注意,被调用的函数永远不应该回调到Julia。

低级同步原语

这些构建块用于创建常规同步对象。

SpinLock()

创建一个非重入,测试和测试和设置自旋锁。 递归使用会导致死锁。 这种锁应该只在执行时间很少且不会阻塞(例如执行I/O)的代码周围使用。 一般说来, 重入锁,重入锁应改为使用。

每个 锁,锁必须与 解锁. 如果 !islocked(lck::SpinLock)持有, trylock(lck)成功,除非有其他任务试图保持锁"在同一时间。"

Test-and-test-and-set自旋锁最快可达约300个线程。 如果您有更多的争用,则应考虑不同的同步方法。

任务指标(实验)

Base.Experimental.task_metrics(::Bool)

启用或禁用每个任务指标的集合。 A 任务 创建于 基地。实验性的。task_metrics(true) 实际上会有 基地。实验性的。task_running_time_ns基地。实验性的。任务_wall_time_ns可用的定时信息。

注意任务指标可以在启动时通过 --任务-指标=是 命令行选项。

Base.Experimental.task_running_time_ns(t::Task) -> Union{UInt64, Nothing}

返回任务的总纳秒 t 已经花了跑步。 此指标仅在以下情况下更新 t 产量或完成,除非 t 是当前任务,其中它将不断更新。 请参阅 基地。实验性的。任务_wall_time_ns.

申报表 什么都没有 如果未启用任务计时。 见 基地。实验性的。任务_metrics.

这个指标来自Julia调度程序,一个任务可能在一个操作系统线程上运行,该线程被操作系统调度程序取消调度,这个时间仍然计入该指标。

兼容性

Julia1.12这个方法是在Julia1.12中加入的。

Base.Experimental.task_wall_time_ns(t::Task) -> Union{UInt64, Nothing}

返回任务的总纳秒 t 是可以运行的。 这是从任务第一次进入运行队列到它完成的时间的时间,或者如果任务尚未完成,则直到当前时间。 请参阅 基地。实验性的。task_running_time_ns.

申报表 什么都没有 如果未启用任务计时。 见 基地。实验性的。任务_metrics.

兼容性

Julia1.12这个方法是在Julia1.12中加入的。