多线程
# *`基地。线程。@线程`*-马科罗_
Threads.@threads [schedule] for ... end
一个宏来执行一个 为 循环并联。 迭代空间分配给粗粒度任务。 此策略可由 时间表 争论。 循环的执行等待所有迭代的评估。
产生的任务 @线程 计划于 :默认值 线程池。 这意味着 @线程 不会使用线程从 :互动 threadpool,即使从主线程或交互池中的任务调用。 该 :默认值 threadpool用于计算密集型并行工作负载。
请参阅: @产卵和 pmap 在 分发的. 有关threadpools的更多信息,请参阅以下章节 threadpools。
*扩展帮助*
*语义*
除非调度选项指定了更强的保证,否则由 @线程 宏具有以下语义。
该 @线程 宏以未指定的顺序并可能并发地执行循环体。 它不指定任务和工作线程的确切分配。 每个执行的分配可以是不同的。 循环体代码(包括从其传递调用的任何代码)不得对迭代到任务或执行它们的工作线程的分布做出任何假设。 每次迭代的循环体必须能够独立于其他迭代向前推进,并且不受数据竞争的影响。 因此,迭代之间的无效同步可能会死锁,而不同步的内存访问可能会导致未定义的行为。
例如,上述条件暗示:
*在迭代中获取的锁_must_将在同一迭代中释放。
*使用阻塞基元在迭代之间进行通信,如 频道s是不正确的。
*仅写入不跨迭代共享的位置(除非使用锁或原子操作)。
*除非 :静态 使用schedule,其值为 线程()即使在一次迭代中也可能发生变化。 见 任务迁移.
*调度员*
没有scheduler参数,确切的调度是未指定的,并且在Julia版本中有所不同。 目前, :动态 未指定调度程序时使用。
|
兼容性
朱莉娅1.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.11 |
*`:静态`*
:静态 scheduler为每个线程创建一个任务,并在它们之间平均分配迭代,将每个任务专门分配给每个线程。 特别是,价值 线程()保证在一次迭代内是恒定的。 指定 :静态 是一个错误,如果从另一个内部使用 @线程 循环或从1以外的线程。
|
注 |
*例子*
为了说明不同的调度策略,请考虑以下函数 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循环。
# *`基地。线程。n.前,前`*-函数
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_,将异步代码与当前任务中变量值的更改隔离开来。
|
请注意,如果任务产生,任务运行的线程可能会发生变化,因此 |
|
兼容性
Julia1.3此宏从Julia1.3开始可用。 |
|
兼容性
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
# *`基地。线程。n.线,线`*-函数
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
|
请注意,如果任务产生,则任务运行的线程可能会更改,这称为 |
# *`基地。线程。线程池`*-函数
Threads.threadpool(tid = threadid()) -> Symbol
返回指定线程的threadpool; :默认值, :互动,或 :外国.
请参阅 多线程。
原子操作
# *`原子`*-密码_
不安全指针操作与加载和存储声明为 [医]原子 和 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`*-马科罗_
@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`*-马科罗_
@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`*-马科罗_
@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}. 获取它的任何单个元素都是原子地执行的( :单调 默认情况下订购)。
|
警告访问 |
有关详细信息,请参阅 原子操作以及宏 @原子, @atomiconce, @atomicswap,和 @atomicreplace.
|
兼容性
Julia1.11这种类型需要Julia1.11或更高版本。 |
|
兼容性
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!等。
# *`基地。线程。atomic_cas!`*-函数
Threads.atomic_cas!(x::Atomic{T}, cmp::T, newval::T) where T
原子比较和设置 x
原子地比较值在 x 与 cmp技术. 如果相等,写 新瓦尔 到 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)
# *`基地。线程。atomic_xchg!`*-函数
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
# *`基地。线程。atomic_add!`*-函数
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
# *`基地。线程。atomic_sub!`*-函数
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
# *`基地。线程。atomic_and!`*-函数
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
# *`基地。线程。atomic_nand!`*-函数
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
# *`基地。线程。atomic_xor!`*-函数
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
# *`基地。线程。atomic_max!`*-函数
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
# *`基地。线程。atomic_min!`*-函数
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的 栅栏 指示。
低级同步原语
这些构建块用于创建常规同步对象。
# *`基地。线程。旋转锁,旋转锁`*-类型
SpinLock()
创建一个非重入,测试和测试和设置自旋锁。 递归使用会导致死锁。 这种锁应该只在执行时间很少且不会阻塞(例如执行I/O)的代码周围使用。 一般说来, 重入锁,重入锁应改为使用。
每个 锁,锁必须与 解锁. 如果 !islocked(lck::SpinLock)持有, trylock(lck)成功,除非有其他任务试图保持锁"在同一时间。"
Test-and-test-and-set自旋锁最快可达约300个线程。 如果您有更多的争用,则应考虑不同的同步方法。
任务指标(实验)
# *`基地。实验性的。任务_metrics`*-函数
Base.Experimental.task_metrics(::Bool)
启用或禁用每个任务指标的集合。 A 任务 创建于 基地。实验性的。task_metrics(true) 实际上会有 基地。实验性的。task_running_time_ns和 基地。实验性的。任务_wall_time_ns可用的定时信息。
|
注意任务指标可以在启动时通过 |
# *`基地。实验性的。task_running_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中加入的。 |
# *`基地。实验性的。任务_wall_time_ns`*-函数
Base.Experimental.task_wall_time_ns(t::Task) -> Union{UInt64, Nothing}
返回任务的总纳秒 t 是可以运行的。 这是从任务第一次进入运行队列到它完成的时间的时间,或者如果任务尚未完成,则直到当前时间。 请参阅 基地。实验性的。task_running_time_ns.
申报表 什么都没有 如果未启用任务计时。 见 基地。实验性的。任务_metrics.
|
兼容性
Julia1.12这个方法是在Julia1.12中加入的。 |