Multi-Threading

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

Paralel olarak bir for döngüsü çalıştırmak için bir makro. İterasyon alanı, kaba-granüllü görevlere dağıtılır. Bu politika schedule argümanı ile belirtilebilir. Döngünün yürütülmesi, tüm iterasyonların değerlendirilmesini bekler.

Ayrıca bakınız: @spawn ve Distributed içindeki pmap.

Genişletilmiş yardım

Anlam

Planlama seçeneği tarafından daha güçlü garantiler belirtilmediği sürece, @threads makrosu tarafından yürütülen döngü aşağıdaki anlamlara sahiptir.

@threads makrosu döngü gövdesini belirsiz bir sırada ve potansiyel olarak eşzamanlı olarak yürütür. Görevlerin ve işçi iş parçacıklarının kesin atamalarını belirtmez. Atamalar her yürütme için farklı olabilir. Her iterasyon için döngü gövdesi kodu (buna transitif olarak çağrılan herhangi bir kod da dahildir) iterasyonların görevlere dağıtımı veya bunların yürütüldüğü işçi iş parçacığı hakkında herhangi bir varsayımda bulunmamalıdır. Her iterasyon için döngü gövdesi, diğer iterasyonlardan bağımsız olarak ileriye doğru ilerleme yapabilmeli ve veri yarışlarından arınmış olmalıdır. Bu nedenle, iterasyonlar arasında geçersiz senkronizasyonlar kilitlenmelere neden olabilirken, senkronize edilmemiş bellek erişimleri tanımsız davranışa yol açabilir.

Örneğin, yukarıdaki koşullar şunları ima eder:

  • Bir iterasyonda alınan bir kilit aynı iterasyonda serbest bırakılmalıdır.
  • Channel gibi engelleyici ilkelere dayanarak iterasyonlar arasında iletişim kurmak yanlıştır.
  • Sadece iterasyonlar arasında paylaşılmayan konumlara yazılmalıdır (bir kilit veya atomik işlem kullanılmadıkça).
  • :static planlaması kullanılmadıkça, threadid() değeri tek bir iterasyon içinde bile değişebilir. Görev Göçü bölümüne bakın.

Planlayıcılar

Planlayıcı argümanı olmadan, kesin planlama belirtilmemiştir ve Julia sürümleri arasında değişir. Şu anda, planlayıcı belirtilmediğinde :dynamic kullanılmaktadır.

Julia 1.5

schedule argümanı Julia 1.5 itibarıyla mevcuttur.

:dynamic (varsayılan)

:dynamic planlayıcısı, iterasyonları mevcut işçi iş parçacıklarına dinamik olarak yürütür. Mevcut uygulama, her iterasyon için iş yükünün eşit olduğunu varsayar. Ancak, bu varsayım gelecekte kaldırılabilir.

Bu planlama seçeneği, temel yürütme mekanizmasına yalnızca bir ipucudur. Ancak, birkaç özellik beklenebilir. :dynamic planlayıcısı tarafından kullanılan Task sayısı, mevcut işçi iş parçacıklarının sayısının küçük bir sabit katı ile sınırlıdır (Threads.threadpoolsize()). Her görev, iterasyon alanının bitişik bölgelerini işler. Bu nedenle, @threads :dynamic for x in xs; f(x); end genellikle @sync for x in xs; @spawn f(x); end'den daha verimlidir, eğer length(xs) işçi iş parçacıklarının sayısından önemli ölçüde daha büyükse ve f(x)'in çalışma süresi, bir görevi başlatma ve senkronize etme maliyetinden (genellikle 10 mikro saniyeden az) nispeten daha küçükse.

Julia 1.8

schedule argümanı için :dynamic seçeneği mevcut ve varsayılan olarak Julia 1.8 itibarıyla mevcuttur.

:greedy

:greedy planlayıcısı, her biri üretilen değerler üzerinde açgözlü bir şekilde çalışan Threads.threadpoolsize() kadar görev başlatır. Bir görev işini bitirir bitirmez, iteratörden bir sonraki değeri alır. Herhangi bir bireysel görev tarafından yapılan iş, iteratörden bitişik değerler üzerinde olmayabilir. Verilen iteratör sonsuza kadar değer üretebilir, yalnızca iteratör arayüzü gereklidir (indeksleme yok).

Bu planlama seçeneği, bireysel iterasyonların iş yükü eşit değilse/büyük bir yayılma varsa genellikle iyi bir seçimdir.

Julia 1.11

schedule argümanı için :greedy seçeneği Julia 1.11 itibarıyla mevcuttur.

:static

:static planlayıcısı, her iş parçacığı için bir görev oluşturur ve iterasyonları eşit olarak böler, her görevi belirli bir iş parçacığına atar. Özellikle, threadid() değeri bir iterasyon içinde sabit olacağına dair garanti vardır. Başka bir @threads döngüsünden veya 1 dışındaki bir iş parçacığından kullanıldığında :static belirtmek bir hatadır.

Not

:static planlaması, Julia 1.3'ten önce yazılmış kodun geçişini desteklemek için mevcuttur. Yeni yazılmış kütüphane işlevlerinde, bu seçeneği kullanan işlevlerin rastgele işçi iş parçacıklarından çağrılamayacağı için :static planlaması önerilmez.

Örnekler

Farklı planlama stratejilerini göstermek için, belirli bir süre boyunca çalışan bir zamanlayıcı döngüsü içeren busywait fonksiyonunu düşünü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)

:dynamic örneği 2 saniye sürer çünkü boşta olan iş parçacıklarından biri, for döngüsünü tamamlamak için iki 1 saniyelik iterasyonu çalıştırabilir. ```

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

foreach(f, channel) ile benzer, ancak channel üzerinde yineleme ve f'ye yapılan çağrılar, Threads.@spawn tarafından başlatılan ntasks görevine dağıtılır. Bu fonksiyon, tüm dahili olarak başlatılan görevlerin tamamlanmasını bekleyecektir.

Eğer schedule isa FairSchedule ise, Threads.foreach görevleri, Julia'nın zamanlayıcısının iş öğelerini daha serbest bir şekilde iş parçacıkları arasında yük dengelemesi yapabilmesi için başlatmaya çalışacaktır. Bu yaklaşım genellikle her bir öğe için daha yüksek bir yükleme süresine sahiptir, ancak diğer çok iş parçacıklı iş yükleri ile birlikte StaticSchedule'dan daha iyi performans gösterebilir.

Eğer schedule isa StaticSchedule ise, Threads.foreach görevleri, FairSchedule'dan daha düşük bir her bir öğe için yükleme süresi ile başlatacaktır, ancak yük dengelemesine daha az uygundur. Bu yaklaşım, ince taneli, homojen iş yükleri için daha uygun olabilir, ancak diğer çok iş parçacıklı iş yükleri ile birlikte FairSchedule'dan daha kötü performans gösterebilir.

Örnekler

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]
Julia 1.6

Bu fonksiyon Julia 1.6 veya daha yenisini gerektirir.

source
Base.Threads.@spawnMacro
Threads.@spawn [:default|:interactive] expr

Bir Task oluşturur ve belirtilen thread havuzunda (belirtilmezse :default) çalışması için schedule eder. Görev, bir thread mevcut olduğunda ona tahsis edilir. Görevin bitmesini beklemek için, bu makronun sonucunda wait çağrısı yapabilir veya fetch çağrısı yaparak bekleyip dönen değerini alabilirsiniz.

Değerler, $ aracılığıyla @spawn içine interpolasyon yapılabilir; bu, değeri doğrudan oluşturulan alt kapanıma kopyalar. Bu, bir değişkenin değerini eklemenizi sağlar ve asenkron kodu mevcut görevdeki değişkenin değerindeki değişikliklerden izole eder.

Not

Görevin çalıştığı thread, görev yield ettiğinde değişebilir; bu nedenle threadid() bir görev için sabit olarak değerlendirilmemelidir. Daha fazla önemli uyarılar için Task Migration ve daha geniş çoklu iş parçacığı kılavuzuna bakın. Ayrıca thread havuzları bölümüne de bakın.

Julia 1.3

Bu makro, Julia 1.3 itibarıyla mevcuttur.

Julia 1.4

$ aracılığıyla değerlerin interpolasyonu, Julia 1.4 itibarıyla mevcuttur.

Julia 1.9

Bir thread havuzu, Julia 1.9 itibarıyla belirtilebilir.

Örnekler

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
source
Base.Threads.threadidFunction
Threads.threadid() -> Int

Geçerli yürütme ipliğinin kimlik numarasını alır. Ana iplik 1 kimliğine sahiptir.

Örnekler

julia> Threads.threadid()
1

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

Bir görevin çalıştığı iplik, görev verirse değişebilir; bu duruma Görev Göçü denir. Bu nedenle, çoğu durumda threadid()'yi bir tampon veya durum nesneleri vektörüne indekslemek için kullanmak güvenli değildir.

source
Base.Threads.maxthreadidFunction
Threads.maxthreadid() -> Int

Julia işlemi için mevcut olan (tüm iş parçacığı havuzları arasında) iş parçacığı sayısının alt sınırını atomic-acquire semantiği ile alın. Sonuç, her zaman threadid() ve threadid(task) için gözlemleyebildiğiniz herhangi bir görev için büyük veya eşit olacaktır.

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

Belirtilen iş parçacığı havuzundaki mevcut iş parçacığı sayısını alır. :interactive içindeki iş parçacıkları 1:nthreads(:interactive) kimlik numaralarına sahiptir ve :default içindeki iş parçacıkları nthreads(:interactive) .+ (1:nthreads(:default)) kimlik numaralarına sahiptir.

Ayrıca LinearAlgebra standart kütüphanesindeki BLAS.get_num_threads ve BLAS.set_num_threads ile Distributed standart kütüphanesindeki nprocs() ve Threads.maxthreadid() ile de bakabilirsiniz.

source
Base.Threads.threadpoolFunction
Threads.threadpool(tid = threadid()) -> Symbol

Belirtilen iş parçacığının iş parçacığı havuzunu döndürür; ya :default, :interactive veya :foreign.

source
Base.Threads.nthreadpoolsFunction
Threads.nthreadpools() -> Int

Mevcut yapılandırılmış iş parçacığı havuzlarının sayısını döndürür.

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

Varsayılan iş parçacığı havuzuna (veya belirtilen iş parçacığı havuzuna) mevcut olan iş parçacığı sayısını alır.

Ayrıca bkz: BLAS.get_num_threads ve BLAS.set_num_threads LinearAlgebra standart kütüphanesinde, ve nprocs() Distributed standart kütüphanesinde.

source
Base.Threads.ngcthreadsFunction
Threads.ngcthreads() -> Int

Şu anda yapılandırılmış olan GC iş parçacıklarının sayısını döndürür. Bu, hem işaretleme iş parçacıklarını hem de eşzamanlı tarama iş parçacıklarını içerir.

source

Ayrıca Multi-Threading'e bakın.

Atomic operations

Base.@atomicMacro
@atomic var
@atomic order ex

var veya ex atomik olarak gerçekleştirilecektir, eğer ex desteklenen bir ifade ise. Eğer order belirtilmemişse, varsayılan olarak :sequentially_consistent kullanılır.

@atomic a.b.x = new
@atomic a.b.x += addend
@atomic :release a.b.x = new
@atomic :acquire_release a.b.x += addend

Sağda ifade edilen depolama işlemini atomik olarak gerçekleştir ve yeni değeri döndür.

= ile bu işlem, setproperty!(a.b, :x, new) çağrısına dönüşür. Herhangi bir operatör ile de bu işlem, modifyproperty!(a.b, :x, +, addend)[2] çağrısına dönüşür.

@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

Sağda ifade edilen ikili işlemi atomik olarak gerçekleştir. Sonucu ilk argümandaki alana depola ve (eski, yeni) değerlerini döndür.

Bu işlem, modifyproperty!(a.b, :x, func, arg2) çağrısına dönüşür.

Daha fazla ayrıntı için kılavuzdaki Alan başına atomikler bölümüne bakın.

Örnekler

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

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

julia> @atomic a.x # a'nın x alanını, sıralı tutarlılıkla al
1

julia> @atomic :sequentially_consistent a.x = 2 # a'nın x alanını, sıralı tutarlılıkla ayarla
2

julia> @atomic a.x += 1 # a'nın x alanını, sıralı tutarlılıkla artır
3

julia> @atomic a.x + 1 # a'nın x alanını, sıralı tutarlılıkla artır
3 => 4

julia> @atomic a.x # a'nın x alanını, sıralı tutarlılıkla al
4

julia> @atomic max(a.x, 10) # a'nın x alanını maksimum değere, sıralı tutarlılıkla değiştir
4 => 10

julia> @atomic a.x max 5 # yine a'nın x alanını maksimum değere, sıralı tutarlılıkla değiştir
10 => 10
Julia 1.7

Bu işlevsellik en az Julia 1.7'yi gerektirir.

```

source
Base.@atomicswapMacro
@atomicswap a.b.x = new
@atomicswap :sequentially_consistent a.b.x = new

new değerini a.b.x'e kaydeder ve a.b.x'in eski değerini döndürür.

Bu işlem, swapproperty!(a.b, :x, new) çağrısına karşılık gelir.

Daha fazla ayrıntı için kılavuzdaki Alan bazında atomikler bölümüne bakın.

Örnekler

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

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

julia> @atomicswap a.x = 2+2 # a'nın x alanını 4 ile değiştir, sıralı tutarlılıkla
1

julia> @atomic a.x # a'nın x alanını al, sıralı tutarlılıkla
4
Julia 1.7

Bu işlevsellik en az Julia 1.7'yi gerektirir.

source
Base.@atomicreplaceMacro
@atomicreplace a.b.x beklenen => istenen
@atomicreplace :sıralı_tutarlı a.b.x beklenen => istenen
@atomicreplace :sıralı_tutarlı :monotonik a.b.x beklenen => istenen

Koşullu değişimi atomik olarak gerçekleştirerek (eski, başarı::Bool) değerlerini döndürün. Burada başarı, değişimin tamamlanıp tamamlanmadığını gösterir.

Bu işlem, replaceproperty!(a.b, :x, beklenen, istenen) çağrısına karşılık gelir.

Daha fazla bilgi için kılavuzdaki Alan başına atomikler bölümüne bakın.

Örnekler

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

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

julia> @atomicreplace a.x 1 => 2 # a'nın x alanını 1 ise 2 ile değiştir, sıralı tutarlılık ile
(eski = 1, başarı = true)

julia> @atomic a.x # a'nın x alanını al, sıralı tutarlılık ile
2

julia> @atomicreplace a.x 1 => 2 # a'nın x alanını 1 ise 2 ile değiştir, sıralı tutarlılık ile
(eski = 2, başarı = false)

julia> xchg = 2 => 0; # a'nın x alanını 2 ise 0 ile değiştir, sıralı tutarlılık ile

julia> @atomicreplace a.x xchg
(eski = 2, başarı = true)

julia> @atomic a.x # a'nın x alanını al, sıralı tutarlılık ile
0
Julia 1.7

Bu işlevsellik en az Julia 1.7'yi gerektirir.

source
Base.@atomiconceMacro
@atomiconce a.b.x = value
@atomiconce :sequentially_consistent a.b.x = value
@atomiconce :sequentially_consistent :monotonic a.b.x = value

Değeri atomik olarak, daha önce ayarlanmamışsa koşullu olarak atayın ve `success::Bool` değerini döndürün. Burada `success`, atamanın tamamlanıp tamamlanmadığını gösterir.

Bu işlem, `setpropertyonce!(a.b, :x, value)` çağrısına karşılık gelir.

Daha fazla bilgi için kılavuzdaki [Alan başına atomikler](@ref man-atomics) bölümüne bakın.

# Örnekler

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

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

julia> @atomiconce a.x = 1 # a'nın x alanını 1 olarak ayarla, eğer ayarlanmamışsa, sıralı tutarlılıkla true

julia> @atomic a.x # a'nın x alanını al, sıralı tutarlılıkla 1

julia> @atomiconce a.x = 1 # a'nın x alanını 1 olarak ayarla, eğer ayarlanmamışsa, sıralı tutarlılıkla false


!!! compat "Julia 1.11"
    Bu işlevsellik en az Julia 1.11 gerektirir.
source
Core.AtomicMemoryType
AtomicMemory{T} == GenericMemory{:atomic, T, Core.CPU}

Sabit boyutlu DenseVector{T}. Elemanlarına erişim atomik olarak gerçekleştirilir (:monotonic sıralaması ile). Elemanlardan herhangi birinin ayarlanması @atomic makrosu kullanılarak ve sıralamanın açıkça belirtilmesiyle gerçekleştirilmelidir.

Warning

Her bir eleman erişildiğinde bağımsız olarak atomiktir ve atomik olmayan bir şekilde ayarlanamaz. Şu anda @atomic makrosu ve daha yüksek seviyeli arayüz tamamlanmamıştır, ancak gelecekteki bir uygulama için yapı taşları içsel intrinziklerdir: Core.memoryrefget, Core.memoryrefset!, Core.memoryref_isassigned, Core.memoryrefswap!, Core.memoryrefmodify! ve Core.memoryrefreplace!.

Detaylar için Atomic Operations sayfasına bakın.

Julia 1.11

Bu tür, Julia 1.11 veya daha yenisini gerektirir.

source

unsafe setindeki işlevler için, bu atomik işlemlerin C/C++ uyumlu sürümlerini seçen isteğe bağlı bellek sıralama parametreleri de vardır; eğer bu parametre unsafe_load, unsafe_store!, unsafe_swap!, unsafe_replace! ve unsafe_modify! olarak belirtilirse.

Warning

Aşağıdaki API'ler kullanımdan kaldırılmıştır, ancak bunlar için destek muhtemelen birkaç sürüm boyunca devam edecektir.

Base.Threads.AtomicType
Threads.Atomic{T}

Bir T türünde bir nesneye referans tutar ve bunun yalnızca atomik olarak, yani bir iş parçacığına güvenli bir şekilde erişilmesini sağlar.

Yalnızca belirli "basit" türler atomik olarak kullanılabilir; bunlar, ilkel boolean, tam sayı ve kayan nokta türleridir. Bunlar Bool, Int8...Int128, UInt8...UInt128 ve Float16...Float64'tür.

Yeni atomik nesneler, atomik olmayan değerlerden oluşturulabilir; eğer belirtilmezse, atomik nesne sıfır ile başlatılır.

Atomik nesnelere [] notasyonu kullanılarak erişilebilir:

Örnekler

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

julia> x[] = 1
1

julia> x[]
1

Atomik işlemler atomic_ ön eki kullanır, örneğin atomic_add!, atomic_xchg! vb.

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

Atomik olarak x'i karşılaştır ve ayarla

x'deki değeri cmp ile atomik olarak karşılaştırır. Eğer eşitse, newval'i x'e yazar. Aksi takdirde, x'i değiştirmeden bırakır. x'deki eski değeri döner. Dönen değeri cmp ile karşılaştırarak (=== aracılığıyla) x'in değiştirilip değiştirilmediğini ve artık yeni değer newval'i tutup tutmadığını bilirsiniz.

Daha fazla ayrıntı için, LLVM'nin cmpxchg talimatına bakın.

Bu fonksiyon, işlemci semantiğini uygulamak için kullanılabilir. İşlemden önce, x'deki değeri kaydedersiniz. İşlemden sonra, yeni değer yalnızca x o sırada değiştirilmemişse saklanır.

Örnekler

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)
source
Base.Threads.atomic_xchg!Function
Threads.atomic_xchg!(x::Atomic{T}, newval::T) where T

x içindeki değeri atomik olarak değiştirir.

x içindeki değeri newval ile atomik olarak değiştirir. Eski değeri döner.

Daha fazla ayrıntı için LLVM'nin atomicrmw xchg talimatına bakın.

Örnekler

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

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

julia> x[]
2
source
Base.Threads.atomic_add!Function
Threads.atomic_add!(x::Atomic{T}, val::T) where T <: ArithmeticTypes

Atomik olarak val değerini x'e ekler.

x[] += val işlemini atomik olarak gerçekleştirir. Eski değeri döner. Atomic{Bool} için tanımlı değildir.

Daha fazla ayrıntı için LLVM'nin atomicrmw add talimatına bakın.

Örnekler

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

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

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

valx'ten atomik olarak çıkarır.

x[] -= val işlemini atomik olarak gerçekleştirir. Eski değeri döner. Atomic{Bool} için tanımlı değildir.

Daha fazla ayrıntı için LLVM'nin atomicrmw sub talimatına bakın.

Örnekler

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

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

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

Atomik olarak x ile val'i bit düzeyinde ve işlemi yapar.

x[] &= val işlemini atomik olarak gerçekleştirir. Eski değeri döner.

Daha fazla ayrıntı için, LLVM'nin atomicrmw and talimatına bakın.

Örnekler

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

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

julia> x[]
2
source
Base.Threads.atomic_nand!Function
Threads.atomic_nand!(x::Atomic{T}, val::T) where T

Atomik olarak x'i val ile bitwise-nand (not-and) yapar.

x[] = ~(x[] & val) işlemini atomik olarak gerçekleştirir. Eski değeri döner.

Daha fazla ayrıntı için, LLVM'nin atomicrmw nand talimatına bakın.

Örnekler

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

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

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

x ile val'ı atomik olarak bitwise-or yapar.

x[] |= val işlemini atomik olarak gerçekleştirir. Eski değeri döner.

Daha fazla ayrıntı için LLVM'nin atomicrmw or talimatına bakın.

Örnekler

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

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

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

Atomik olarak x'i val ile bit düzeyinde XOR (özel veya) işlemi yapar.

x[] $= val işlemini atomik olarak gerçekleştirir. Eski değeri döner.

Daha fazla ayrıntı için LLVM'nin atomicrmw xor talimatına bakın.

Örnekler

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

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

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

x ve val'in maksimumunu atomik olarak x'e kaydedin

Atomik olarak x[] = max(x[], val) işlemini gerçekleştirir. Eski değeri döndürür.

Daha fazla ayrıntı için, LLVM'nin atomicrmw max talimatına bakın.

Örnekler

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

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

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

x ve val'in minimumunu atomik olarak x'e kaydedin

Atomik olarak x[] = min(x[], val) işlemini gerçekleştirir. Eski değeri döndürür.

Daha fazla ayrıntı için, LLVM'nin atomicrmw min talimatına bakın.

Örnekler

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

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

julia> x[]
5
source
Base.Threads.atomic_fenceFunction
Threads.atomic_fence()

Sıralı tutarlılık bellek engeli ekleyin

Sıralı tutarlılık sıralama anlamsalara sahip bir bellek engeli ekler. Bunun gerekli olduğu, yani bir edinme/salım sıralamasının yetersiz olduğu algoritmalar vardır.

Bu muhtemelen çok pahalı bir işlemdir. Julia'daki diğer tüm atomik işlemlerin zaten edinme/salım anlamsalara sahip olduğu göz önüne alındığında, açık engeller çoğu durumda gerekli olmamalıdır.

Daha fazla ayrıntı için, LLVM'nin fence talimatına bakın.

source

ccall using a libuv threadpool (Experimental)

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

@threadcall makrosu, ccall ile aynı şekilde çağrılır, ancak işi farklı bir iş parçacığında yapar. Bu, mevcut julia iş parçacığının engellenmeden bir engelleyici C fonksiyonunu çağırmak istediğinizde yararlıdır. Eşzamanlılık, libuv iş parçacığı havuzunun boyutuyla sınırlıdır; varsayılan olarak 4 iş parçacığıdır, ancak UV_THREADPOOL_SIZE ortam değişkenini ayarlayarak ve julia sürecini yeniden başlatarak artırılabilir.

Çağrılan fonksiyonun asla Julia'ya geri çağrıda bulunmaması gerektiğini unutmayın.

source

Low-level synchronization primitives

Bu yapı taşları, düzenli senkronizasyon nesnelerini oluşturmak için kullanılır.

Base.Threads.SpinLockType
SpinLock()

Reentransız, test-et-test-et-ve-kur kilidi oluşturun. Rekürsif kullanım bir ölü kilitlenmeye yol açacaktır. Bu tür bir kilit, yalnızca kısa sürede çalıştırılan ve engellemeyen (örneğin, I/O gerçekleştiren) kod etrafında kullanılmalıdır. Genel olarak, ReentrantLock bunun yerine kullanılmalıdır.

Her lock bir unlock ile eşleştirilmelidir. Eğer !islocked(lck::SpinLock) geçerliyse, trylock(lck) başarılı olur, aksi takdirde kilidi "aynı anda" tutmaya çalışan başka görevler varsa başarısız olur.

Test-et-test-et-ve-kur spin kilitleri, yaklaşık 30 civarında rekabet eden iş parçacığına kadar en hızlıdır. Eğer bundan daha fazla rekabet varsa, farklı senkronizasyon yaklaşımları düşünülmelidir.

source