Tasks

Core.TaskType
Görev(func)

Verilen func fonksiyonunu (argüman almayan bir çağrılabilir olmalıdır) yürütmek için bir Görev (yani coroutine) oluşturun. Görev, bu fonksiyon döndüğünde sona erer. Görev, schedule ile yapılandırıldığında, inşaat sırasında ebeveynin "dünya yaşı" içinde çalışacaktır.

!!! uyarı Varsayılan olarak görevlerin yapışkan bitinin t.sticky olarak ayarlandığına dikkat edin. Bu, @async için tarihsel varsayılanı modellemektedir. Yapışkan görevler yalnızca ilk olarak planlandıkları işçi iş parçacığında çalıştırılabilir ve planlandıklarında, planlandıkları görev yapışkan hale gelecektir. Threads.@spawn davranışını elde etmek için yapışkan bitini manuel olarak false olarak ayarlayın.

Örnekler

julia> a() = sum(i for i in 1:1000);

julia> b = Task(a);

Bu örnekte, b henüz başlamamış bir çalıştırılabilir Görevdir.

source
Base.@taskMacro
@task

Bir ifadeyi çalıştırmadan Task içine sarın ve Task döndürün. Bu yalnızca bir görev oluşturur ve çalıştırmaz.

Warning

Varsayılan olarak görevlerin yapışkan bitinin true olarak ayarlanmış olacaktır t.sticky. Bu, @async için tarihsel varsayılanı modellemektedir. Yapışkan görevler yalnızca ilk olarak planlandıkları işçi iş parçacığında çalıştırılabilir ve planlandıklarında, planlandıkları görev yapışkan hale gelecektir. Threads.@spawn davranışını elde etmek için yapışkan bitini manuel olarak false olarak ayarlayın.

Örnekler

julia> a1() = sum(i for i in 1:1000);

julia> b = @task a1();

julia> istaskstarted(b)
false

julia> schedule(b);

julia> yield();

julia> istaskdone(b)
true
source
Base.@asyncMacro
@async

Bir ifadeyi Task içine sarın ve yerel makinenin zamanlayıcı kuyruğuna ekleyin.

Değerler, $ aracılığıyla @async 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.

Warning

@async yerine her zaman Threads.@spawn kullanmanız şiddetle tavsiye edilir paralellik gereksinimi olmasa bile, özellikle kamuya açık dağıtılan kütüphanelerde. Bunun nedeni, @async kullanımının, Julia'nın mevcut uygulamasında ebeveyn görevlerin işçi iş parçacıkları arasında taşınmasını devre dışı bırakmasıdır. Bu nedenle, bir kütüphane fonksiyonunda @async kullanımının görünüşte masum bir şekilde, kullanıcı uygulamalarının çok farklı bölümlerinin performansı üzerinde büyük bir etkisi olabilir.

Julia 1.4

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

source
Base.asyncmapFunction
asyncmap(f, c...; ntasks=0, batch_size=nothing)

Bir koleksiyon (veya birden fazla eşit uzunlukta koleksiyon) üzerinde f'yi eşzamanlı görevler kullanarak haritalar. Birden fazla koleksiyon argümanı için, f eleman bazında uygulanır.

ntasks, eşzamanlı olarak çalıştırılacak görev sayısını belirtir. Koleksiyonların uzunluğuna bağlı olarak, ntasks belirtilmemişse, eşzamanlı haritalama için en fazla 100 görev kullanılacaktır.

ntasks, ayrıca sıfır argümanlı bir fonksiyon olarak da belirtilebilir. Bu durumda, her bir elemanı işlemden önce paralel olarak çalıştırılacak görev sayısı kontrol edilir ve ntasks_func değeri mevcut görev sayısından büyükse yeni bir görev başlatılır.

batch_size belirtilirse, koleksiyon toplu modda işlenir. Bu durumda, f, bir Vector argüman demetleri kabul eden ve bir sonuç vektörü döndüren bir fonksiyon olmalıdır. Girdi vektörünün uzunluğu batch_size veya daha az olacaktır.

Aşağıdaki örnekler, haritalama fonksiyonunun çalıştırıldığı görevlerin objectid'sini döndürerek farklı görevlerdeki yürütmeyi vurgular.

Öncelikle, ntasks tanımlanmamışken, her bir eleman farklı bir görevde işlenir.

julia> tskoid() = objectid(current_task());

julia> asyncmap(x->tskoid(), 1:5)
5-element Array{UInt64,1}:
 0x6e15e66c75c75853
 0x440f8819a1baa682
 0x9fb3eeadd0c83985
 0xebd3e35fe90d4050
 0x29efc93edce2b961

julia> length(unique(asyncmap(x->tskoid(), 1:5)))
5

ntasks=2 ile tüm elemanlar 2 görevde işlenir.

julia> asyncmap(x->tskoid(), 1:5; ntasks=2)
5-element Array{UInt64,1}:
 0x027ab1680df7ae94
 0xa23d2f80cd7cf157
 0x027ab1680df7ae94
 0xa23d2f80cd7cf157
 0x027ab1680df7ae94

julia> length(unique(asyncmap(x->tskoid(), 1:5; ntasks=2)))
2

batch_size tanımlandığında, haritalama fonksiyonu bir argüman demetleri dizisini kabul edecek ve bir sonuç dizisi döndürecek şekilde değiştirilmelidir. Bunu başarmak için değiştirilmiş haritalama fonksiyonunda map kullanılır.

julia> batch_func(input) = map(x->string("args_tuple: ", x, ", element_val: ", x[1], ", task: ", tskoid()), input)
batch_func (generic function with 1 method)

julia> asyncmap(batch_func, 1:5; ntasks=2, batch_size=2)
5-element Array{String,1}:
 "args_tuple: (1,), element_val: 1, task: 9118321258196414413"
 "args_tuple: (2,), element_val: 2, task: 4904288162898683522"
 "args_tuple: (3,), element_val: 3, task: 9118321258196414413"
 "args_tuple: (4,), element_val: 4, task: 4904288162898683522"
 "args_tuple: (5,), element_val: 5, task: 9118321258196414413"
source
Base.asyncmap!Function
asyncmap!(f, results, c...; ntasks=0, batch_size=nothing)

asyncmap gibi, ancak çıktıyı bir koleksiyon döndürmek yerine results içinde saklar.

!!! uyarı Herhangi bir değiştirilmiş argümanın başka bir argümanla bellek paylaşması durumunda davranış beklenmedik olabilir.

source
Base.istaskdoneFunction
istaskdone(t::Task) -> Bool

Bir görevin sona erip ermediğini belirleyin.

Örnekler

julia> a2() = sum(i for i in 1:1000);

julia> b = Task(a2);

julia> istaskdone(b)
false

julia> schedule(b);

julia> yield();

julia> istaskdone(b)
true
source
Base.istaskstartedFunction
istaskstarted(t::Task) -> Bool

Bir görevin çalışmaya başlayıp başlamadığını belirleyin.

Örnekler

julia> a3() = sum(i for i in 1:1000);

julia> b = Task(a3);

julia> istaskstarted(b)
false
source
Base.istaskfailedFunction
istaskfailed(t::Task) -> Bool

Bir görevin bir istisna atıldığı için çıkıp çıkmadığını belirleyin.

Örnekler

julia> a4() = error("görev başarısız");

julia> b = Task(a4);

julia> istaskfailed(b)
false

julia> schedule(b);

julia> yield();

julia> istaskfailed(b)
true
Julia 1.3

Bu fonksiyon en az Julia 1.3 gerektirir.

source
Base.task_local_storageMethod
task_local_storage(key)

Mevcut görevin görev-yerel depolamasında bir anahtarın değerini kontrol edin.

source
Base.task_local_storageMethod
task_local_storage(body, key, value)

valuekey'e atayarak değiştirilmiş görev-yerel depolama ile body fonksiyonunu çağırır; key'in önceki değeri veya yokluğu daha sonra geri yüklenir. Dinamik kapsamı taklit etmek için yararlıdır.

source

Scheduling

Base.yieldFunction
yield()

Başka bir planlanmış görevin çalışmasına izin vermek için zamanlayıcıya geçin. Bu işlevi çağıran bir görev hala çalıştırılabilir durumdadır ve başka çalıştırılabilir görev yoksa hemen yeniden başlatılacaktır.

source
yield(t::Task, arg = nothing)

schedule(t, arg); yield()'in hızlı, adaletsiz zamanlama versiyonu olan bu fonksiyon, zamanlayıcıyı çağırmadan önce hemen t'ye geçiş yapar.

source
Base.yieldtoFunction
yieldto(t::Task, arg = nothing)

Verilen göreve geçiş yapar. Bir göreve ilk kez geçildiğinde, görevin fonksiyonu hiçbir argüman olmadan çağrılır. Sonraki geçişlerde, arg son yieldto çağrısından döner. Bu, yalnızca görevleri değiştiren, durumları veya zamanlamayı dikkate almayan düşük seviyeli bir çağrıdır. Kullanımı önerilmez.

source
Base.sleepFunction
sleep(seconds)

Mevcut görevi belirtilen sayıda saniye boyunca engeller. Minimum uyku süresi 1 milisaniye veya 0.001 girişi kadardır.

source
Base.scheduleFunction
schedule(t::Task, [val]; error=false)

Bir Task zamanlayıcının kuyruğuna eklenir. Bu, sistem başka bir şey yapmadığında görevin sürekli çalışmasını sağlar, ancak görev wait gibi bir engelleyici işlem yapıyorsa bu durum geçerli değildir.

İkinci bir argüman val sağlanırsa, bu değer görev tekrar çalıştığında (yieldto aracılığıyla) göreve iletilecektir. Eğer error true ise, değer uyanan görevde bir istisna olarak yükseltilir.

!!! uyarı Zaten başlatılmış bir Task üzerinde schedule kullanmak yanlıştır. Daha fazla bilgi için API referansına bakın.

!!! uyarı Varsayılan olarak görevlerin yapışkan bitinin true olarak ayarlandığı t.sticky olacaktır. Bu, @async için tarihsel varsayılanı modellemektedir. Yapışkan görevler yalnızca ilk olarak planlandıkları işçi iş parçacığında çalıştırılabilir ve planlandıklarında, planlandıkları görev yapışkan hale gelecektir. Threads.@spawn davranışını elde etmek için yapışkan bitini manuel olarak false olarak ayarlayın.

Örnekler

julia> a5() = sum(i for i in 1:1000);

julia> b = Task(a5);

julia> istaskstarted(b)
false

julia> schedule(b);

julia> yield();

julia> istaskstarted(b)
true

julia> istaskdone(b)
true
source

Synchronization

Base.errormonitorFunction
errormonitor(t::Task)

Görev t başarısız olursa stderr'ye bir hata günlüğü yazdırır.

Örnekler

julia> Base._wait(errormonitor(Threads.@spawn error("görev başarısız oldu")))
Unhandled Task ERROR: görev başarısız oldu
Stacktrace:
[...]
source
Base.@syncMacro
@sync

Tüm sözdizimsel olarak kapsanan @async, @spawn, Distributed.@spawnat ve Distributed.@distributed kullanımlarının tamamlanmasını bekleyin. Kapsanan asenkron işlemler tarafından fırlatılan tüm istisnalar toplanır ve bir CompositeException olarak fırlatılır.

Örnekler

julia> Threads.nthreads()
4

julia> @sync begin
           Threads.@spawn println("Thread-id $(Threads.threadid()), task 1")
           Threads.@spawn println("Thread-id $(Threads.threadid()), task 2")
       end;
Thread-id 3, task 1
Thread-id 1, task 2
source
Base.waitFunction

Threads.Condition için özel not:

Çağrıcı, bu yöntemi çağırmadan önce bir Threads.Condition'a sahip olan lock tutmalıdır. Çağrılan görev, genellikle aynı Threads.Condition nesnesi üzerinde notify çağrılarak başka bir görev tarafından uyandırılana kadar engellenecektir. Engelleme sırasında kilit atomik olarak serbest bırakılacak (kendi kendine kilitlenmiş olsa bile) ve geri dönerken yeniden edinilecektir.

source
wait(r::Future)

Belirtilen Future için bir değerin mevcut olmasını bekleyin.

source
wait(r::RemoteChannel, args...)

Belirtilen RemoteChannel üzerinde bir değerin kullanılabilir hale gelmesini bekleyin.

source
wait([x])

Mevcut görevi, argümanın türüne bağlı olarak bir olay meydana gelene kadar engeller:

  • Channel: Kanalda bir değerin eklenmesini bekleyin.
  • Condition: Bir koşulda notify için bekleyin ve notify'ye geçirilen val parametresini döndürün. Bir koşulda beklemek, ayrıca first=true geçişine izin verir; bu, bekleyenin notify üzerinde uyanmak için sıranın ilk sırasına yerleştirilmesiyle sonuçlanır, bu da genellikle ilk giren ilk çıkar davranışıdır.
  • Process: Bir işlemin veya işlem zincirinin çıkmasını bekleyin. Bir işlemin exitcode alanı, başarı veya başarısızlığı belirlemek için kullanılabilir.
  • Task: Bir Task'ın bitmesini bekleyin. Eğer görev bir istisna ile başarısız olursa, bir TaskFailedException (başarısız olan görevi saran) fırlatılır.
  • RawFD: Bir dosya tanımlayıcısındaki değişiklikleri bekleyin (bkz. FileWatching paketi).

Hiçbir argüman geçilmezse, görev belirsiz bir süre engellenir. Bir görev yalnızca schedule veya yieldto için açık bir çağrı ile yeniden başlatılabilir.

Genellikle wait, beklenen bir koşulun karşılandığından emin olmak için bir while döngüsü içinde çağrılır.

source
wait(c::Channel)

Channel isready olana kadar engeller.

julia> c = Channel(1);

julia> isready(c)
false

julia> task = Task(() -> wait(c));

julia> schedule(task);

julia> istaskdone(task)  # görev engellendi çünkü kanal hazır değil
false

julia> put!(c, 1);

julia> istaskdone(task)  # görev şimdi engellenmedi
true
source
Base.fetchMethod
fetch(t::Task)

Bir Task tamamlanmasını bekleyin, ardından sonuç değerini döndürün. Görev bir istisna ile başarısız olursa, başarısız görevi saran bir TaskFailedException fırlatılır.

source
Base.timedwaitFunction
timedwait(testcb, timeout::Gerçek; pollint::Gerçek=0.1)

testcb() true döndürene kadar veya timeout saniye geçene kadar bekleyin, hangisi daha önce olursa. Test fonksiyonu her pollint saniyede bir kontrol edilir. pollint için minimum değer 0.001 saniyedir, yani 1 milisaniye.

:ok veya :timed_out döndürün.

Örnekler

julia> cb() = (sleep(5); return);

julia> t = @async cb();

julia> timedwait(()->istaskdone(t), 1)
:timed_out

julia> timedwait(()->istaskdone(t), 6.5)
:ok
source
Base.ConditionType
Condition()

Görevlerin bekleyebileceği bir kenar tetiklemeli olay kaynağı oluşturur. Condition üzerinde wait çağrısı yapan görevler askıya alınır ve sıraya alınır. Daha sonra Condition üzerinde notify çağrısı yapıldığında görevler uyandırılır. Bir koşulda beklemek, bir değer döndürebilir veya notify 'nin isteğe bağlı argümanları kullanıldığında bir hata oluşturabilir. Kenar tetikleme, yalnızca notify çağrıldığında bekleyen görevlerin uyandırılabileceği anlamına gelir. Seviye tetiklemeli bildirimler için, bir bildirimin olup olmadığını takip etmek için ekstra bir durum tutmalısınız. Channel ve Threads.Event türleri bunu yapar ve seviye tetiklemeli olaylar için kullanılabilir.

Bu nesne THREAD-GÜVENLİ değildir. Thread-güvenli bir versiyon için Threads.Condition 'e bakın.

source
Base.Threads.ConditionType
Threads.Condition([lock])

Base.Condition için thread güvenli bir versiyon.

Bir Threads.Condition üzerinde wait veya notify çağırmak için önce ona lock çağırmalısınız. wait çağrıldığında, kilit atomik olarak bloklama sırasında serbest bırakılır ve wait döndüğünde yeniden edinilecektir. Bu nedenle, bir Threads.Condition c kullanımı aşağıdaki gibi görünmelidir:

lock(c)
try
    while !thing_we_are_waiting_for
        wait(c)
    end
finally
    unlock(c)
end
Julia 1.2

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

source
Base.EventType
Event([autoreset=false])

Seviye tetikleyici bir olay kaynağı oluşturur. wait çağrısı yapan görevler, Event üzerinde notify çağrısı yapılana kadar askıya alınır ve sıraya alınır. notify çağrısı yapıldıktan sonra, Event bir sinyal durumunda kalır ve görevler artık beklerken engellenmez, ta ki reset çağrısı yapılana kadar.

Eğer autoreset doğruysa, her notify çağrısı için en fazla bir görev wait'ten serbest bırakılacaktır.

Bu, notify/wait üzerinde bir edinme ve serbest bırakma bellek sıralaması sağlar.

Julia 1.1

Bu işlevsellik en az Julia 1.1 gerektirir.

Julia 1.8

autoreset işlevselliği ve bellek sıralama garantisi en az Julia 1.8 gerektirir.

source
Base.notifyFunction
notify(condition, val=nothing; all=true, error=false)

Bir koşulu bekleyen görevleri uyandırın, onlara val geçirin. Eğer all true ise (varsayılan), bekleyen tüm görevler uyandırılır, aksi takdirde yalnızca biri uyandırılır. Eğer error true ise, geçirilen değer uyandırılan görevlerde bir istisna olarak yükseltilir.

Uyandırılan görevlerin sayısını döndürün. Eğer condition üzerinde bekleyen görev yoksa 0 döndürün.

source
Base.resetMethod
reset(::Event)

Bir Event nesnesini ayarlanmamış bir duruma geri döndürür. Daha sonra wait çağrıları, notify tekrar çağrılana kadar engellenecektir.

source
Base.SemaphoreType
Semaphore(sem_size)

En fazla sem_size edinimin kullanılmasına izin veren bir sayım semaforu oluşturur. Her edinim, bir serbest bırakma ile eşleşmelidir.

Bu, edinim/serbest bırakma çağrıları üzerinde bir edinim ve serbest bırakma bellek sıralaması sağlar.

source
Base.acquireFunction
acquire(s::Semaphore)

Bir sem_size izninin mevcut olmasını bekleyin, birinin alınmasını engelleyerek bekleyin.

source
acquire(f, s::Semaphore)

Semaphore s'den alım yaptıktan sonra f'yi çalıştırır ve tamamlandığında veya hata oluştuğunda release eder.

Örneğin, aynı anda yalnızca 2 foo çağrısının aktif olmasını sağlayan bir do-block biçimi:

s = Base.Semaphore(2)
@sync for _ in 1:100
    Threads.@spawn begin
        Base.acquire(s) do
            foo()
        end
    end
end
Julia 1.8

Bu yöntem en az Julia 1.8 gerektirir.

source
Base.releaseFunction
release(s::Semaphore)

Havuzdan bir izin geri verin, bu da başka bir görevin onu almasına ve yürütmeye devam etmesine olanak tanıyabilir.

source
Base.lockFunction
lock(lock)

lock mevcut olduğunda onu edin. Eğer lock başka bir görev/işlem tarafından zaten kilitlenmişse, mevcut hale gelmesini bekleyin.

Her lock, bir unlock ile eşleşmelidir.

source
lock(f::Function, lock)

lock'ı al, lock tutulurken f'yi çalıştır ve f döndüğünde lock'ı serbest bırak. Eğer lock başka bir görev/iş parçacığı tarafından zaten kilitlenmişse, kullanılabilir hale gelene kadar bekle.

Bu fonksiyon döndüğünde, lock serbest bırakılmıştır, bu yüzden çağıran kişi unlock yapmaya çalışmamalıdır.

Ayrıca bakınız: @lock.

Julia 1.7

İkinci argüman olarak bir Channel kullanmak, Julia 1.7 veya daha yenisini gerektirir.

source

lock(f::Function, l::Lockable)

l ile ilişkili kilidi al, f'yi kilitli olarak çalıştır ve f döndüğünde kilidi serbest bırak. f, l tarafından sarılmış olan değeri alan bir konumsal argüman alacaktır. Eğer kilit başka bir görev/işlem tarafından zaten kilitlenmişse, kullanılabilir hale gelene kadar bekle. Bu fonksiyon döndüğünde, lock serbest bırakılmıştır, bu nedenle çağıran kişi onu unlock etmeye çalışmamalıdır.

Julia 1.11

En az Julia 1.11 gerektirir.

source
Base.unlockFunction
unlock(lock)

lock'ın sahipliğini serbest bırakır.

Eğer bu daha önce edinilmiş bir rekürsif kilit ise, dahili bir sayacı azaltır ve hemen döner.

source
Base.trylockFunction
trylock(lock) -> Başarı (Boolean)

Kilidi mevcutsa alır ve başarılıysa true döner. Eğer kilit başka bir görev/iş parçacığı tarafından zaten kilitlenmişse, false döner.

Her başarılı trylock, bir unlock ile eşleşmelidir.

trylock fonksiyonu, islocked ile birleştirildiğinde, eğer typeof(lock) tarafından destekleniyorsa test-et-test-et-ve-set veya üssel geri çekilme algoritmalarını yazmak için kullanılabilir (belgesini okuyun).

source
Base.islockedFunction
islocked(lock) -> Durum (Boolean)

lock'ın herhangi bir görev/iş parçacığı tarafından tutulup tutulmadığını kontrol eder. Bu fonksiyon tek başına senkronizasyon için kullanılmamalıdır. Ancak, islocked ile trylock birleştirildiğinde, test-et-test-et-ve-set veya üssel geri çekilme algoritmalarını yazmak için kullanılabilir eğer typeof(lock) tarafından destekleniyorsa (belgelerini okuyun).

Genişletilmiş yardım

Örneğin, lock uygulaması aşağıda belgelenen özellikleri karşıladıysa, üssel geri çekilme şu şekilde uygulanabilir.

nspins = 0
while true
    while islocked(lock)
        GC.safepoint()
        nspins += 1
        nspins > LIMIT && error("timeout")
    end
    trylock(lock) && break
    backoff()
end

Uygulama

Bir kilit uygulamasının islocked'ı aşağıdaki özelliklerle tanımlaması ve bunu belgelerinde belirtmesi önerilir.

  • islocked(lock) veri yarışı içermemelidir.
  • Eğer islocked(lock) false dönerse, diğer görevlerden herhangi bir müdahale yoksa trylock(lock)'ın hemen çağrılması başarılı olmalıdır ( true döner).
source
Base.ReentrantLockType
ReentrantLock()

Bir Task senkronizasyonu için yeniden giriş kilidi oluşturur. Aynı görev, gerektiği kadar kilidi alabilir (bu, adın "Yeniden Giriş" kısmının anlamıdır). Her lock bir unlock ile eşleşmelidir.

lock çağrısı, ilgili unlock'a kadar o iş parçacığında sonlandırıcıların çalışmasını da engelleyecektir. Aşağıda gösterilen standart kilit deseninin doğal olarak desteklenmesi gerekir, ancak deneme/kilit sırasını tersine çevirmekten veya deneme bloğunu tamamen atlamaktan (örneğin, kilit hala tutulurken geri dönmeye çalışmak) kaçının:

Bu, kilit/açma çağrıları üzerinde bir alma/serbest bırakma bellek sıralaması sağlar.

lock(l)
try
    <atomik iş>
finally
    unlock(l)
end

Eğer !islocked(lck::ReentrantLock) 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.

source
Base.@lockMacro
@lock l expr

lock(f, l::AbstractLock) makrosunun f fonksiyonu yerine expr ile versiyonudur. Aşağıdakine genişler:

lock(l)
try
    expr
finally
    unlock(l)
end

Bu, lock kullanarak bir do bloğu ile benzer, ancak bir kapanış oluşturmaktan kaçınır ve böylece performansı artırabilir.

Uyumluluk

@lock, Julia 1.3'te eklendi ve Julia 1.10'da dışa aktarıldı.

source
Base.LockableType

Lockable(value, lock = ReentrantLock())

value ile birlikte sağlanan lock ile ilişkilendirilmiş bir Lockable nesnesi oluşturur. Bu nesne @lock, lock, trylock, unlock destekler. Değere erişmek için, kilidi tutarken kilitlenebilir nesneyi indeksleyin.

Julia 1.11

En az Julia 1.11 gerektirir.

Örnek

julia> locked_list = Base.Lockable(Int[]);

julia> @lock(locked_list, push!(locked_list[], 1)) # değere erişmek için kilidi tutmalısınız
1-element Vector{Int64}:
 1

julia> lock(summary, locked_list)
"1-element Vector{Int64}"
source

Channels

Base.ChannelType
Channel{T=Any}(size::Int=0)

T türünde size nesnesini tutabilen bir Channel oluşturur. Dolu bir kanalda put! çağrıları, bir nesne take! ile çıkarılana kadar bloklanır.

Channel(0) tamponu olmayan bir kanal oluşturur. put!, eşleşen bir take! çağrılana kadar bloklanır. Ve tersine.

Diğer yapıcılar:

  • Channel(): varsayılan yapıcı, Channel{Any}(0) ile eşdeğerdir
  • Channel(Inf): Channel{Any}(typemax(Int)) ile eşdeğerdir
  • Channel(sz): Channel{Any}(sz) ile eşdeğerdir
Julia 1.3

Varsayılan yapıcı Channel() ve varsayılan size=0, Julia 1.3'te eklendi.

source
Base.ChannelMethod
Channel{T=Any}(func::Function, size=0; taskref=nothing, spawn=false, threadpool=nothing)

func'dan yeni bir görev oluşturun, bunu T türünde ve size boyutunda yeni bir kanala bağlayın ve görevi, hepsini tek bir çağrıda planlayın. Görev sona erdiğinde kanal otomatik olarak kapatılır.

func, bağlı kanalı tek argümanı olarak kabul etmelidir.

Oluşturulan göreve bir referansa ihtiyacınız varsa, anahtar argüman taskref aracılığıyla bir Ref{Task} nesnesi geçirin.

Eğer spawn=true ise, func için oluşturulan Task, paralel olarak başka bir iş parçacığında planlanabilir; bu, bir görevi Threads.@spawn aracılığıyla oluşturmakla eşdeğerdir.

Eğer spawn=true ve threadpool argümanı ayarlanmamışsa, varsayılan olarak :default olur.

Eğer threadpool argmanı ayarlanmışsa (:default veya :interactive olarak), bu spawn=true anlamına gelir ve yeni Görev belirtilen iş parçacığı havuzuna oluşturulur.

Bir Channel döndürün.

Örnekler

julia> chnl = Channel() do ch
           foreach(i -> put!(ch, i), 1:4)
       end;

julia> typeof(chnl)
Channel{Any}

julia> for i in chnl
           @show i
       end;
i = 1
i = 2
i = 3
i = 4

Oluşturulan görevi referans alma:

julia> taskref = Ref{Task}();

julia> chnl = Channel(taskref=taskref) do ch
           println(take!(ch))
       end;

julia> istaskdone(taskref[])
false

julia> put!(chnl, "Hello");
Hello

julia> istaskdone(taskref[])
true
Julia 1.3

spawn= parametresi Julia 1.3'te eklendi. Bu yapıcı Julia 1.3'te eklendi. Daha önceki Julia sürümlerinde, Channel size ve T'yi ayarlamak için anahtar argümanlar kullanıyordu, ancak bu yapıcılar kullanımdan kaldırılmıştır.

Julia 1.9

threadpool= argümanı Julia 1.9'da eklendi.

julia> chnl = Channel{Char}(1, spawn=true) do ch
           for c in "hello world"
               put!(ch, c)
           end
       end
Channel{Char}(1) (2 items available)

julia> String(collect(chnl))
"hello world"
source
Base.put!Method
put!(c::Channel, v)

Kanal c'ye bir öğe v ekler. Kanal doluysa engeller.

Tamponlanmamış kanallar için, farklı bir görev tarafından take! gerçekleştirilene kadar engeller.

Julia 1.1

v, put! çağrıldığında kanalın türüne convert ile dönüştürülür.

source
Base.take!Method
take!(c::Channel)

Bir Channel içinden sırayla bir değeri kaldırır ve döndürür. Veri mevcut olana kadar engeller. Tamponlanmamış kanallar için, başka bir görev tarafından bir put! gerçekleştirilene kadar engeller.

Örnekler

Tamponlu kanal:

julia> c = Channel(1);

julia> put!(c, 1);

julia> take!(c)
1

Tamponsuz kanal:

julia> c = Channel(0);

julia> task = Task(() -> put!(c, 1));

julia> schedule(task);

julia> take!(c)
1
source
Base.isreadyMethod
isready(c::Channel)

Bir Channel içinde bir değer olup olmadığını belirler. Hemen döner, engellemez.

Tamponlanmamış kanallar için, put! üzerinde bekleyen görevler varsa true döner.

Örnekler

Tamponlu kanal:

julia> c = Channel(1);

julia> isready(c)
false

julia> put!(c, 1);

julia> isready(c)
true

Tamponlanmamış kanal:

julia> c = Channel();

julia> isready(c)  # hiçbir görev put! için beklemiyor!
false

julia> task = Task(() -> put!(c, 1));

julia> schedule(task);  # bir put! görevini planla

julia> isready(c)
true
source
Base.fetchMethod
fetch(c::Channel)

İlk mevcut öğeyi Channel'dan (kaldırmadan) bekler ve döndürür. Not: fetch, bir tamponlanmamış (0-boyutlu) Channel üzerinde desteklenmez.

Örnekler

Tamponlu kanal:

julia> c = Channel(3) do ch
           foreach(i -> put!(ch, i), 1:3)
       end;

julia> fetch(c)
1

julia> collect(c)  # öğe kaldırılmaz
3-element Vector{Any}:
 1
 2
 3
source
Base.closeMethod
close(c::Channel[, excp::Exception])

Bir kanalı kapat. Bir istisna (isteğe bağlı olarak excp ile verilen) aşağıdakilerden biri tarafından fırlatılır:

source
Base.bindMethod
bind(chnl::Channel, task::Task)

chnl'nin ömrünü bir görevle ilişkilendirir. Channel chnl, görev sona erdiğinde otomatik olarak kapatılır. Görevde yakalanmamış herhangi bir istisna, chnl üzerindeki tüm bekleyenlere iletilir.

chnl nesnesi, görev sona ermesinden bağımsız olarak açıkça kapatılabilir. Sona eren görevler, zaten kapatılmış Channel nesneleri üzerinde hiçbir etkiye sahip değildir.

Bir kanal birden fazla göreve bağlandığında, ilk sona eren görev kanalı kapatır. Aynı göreve bağlı birden fazla kanal olduğunda, görevin sona ermesi tüm bağlı kanalları kapatır.

Örnekler

julia> c = Channel(0);

julia> task = @async foreach(i->put!(c, i), 1:4);

julia> bind(c,task);

julia> for i in c
           @show i
       end;
i = 1
i = 2
i = 3
i = 4

julia> isopen(c)
false
julia> c = Channel(0);

julia> task = @async (put!(c, 1); error("foo"));

julia> bind(c, task);

julia> take!(c)
1

julia> put!(c, 1);
HATA: TaskFailedException
Stacktrace:
[...]
    nested task error: foo
[...]
source

Low-level synchronization using schedule and wait

schedule en kolay doğru kullanımı henüz başlamamış (planlanmış) bir Task üzerindedir. Ancak, 4d61726b646f776e2e436f64652822222c20227363686564756c652229_40726566 ve wait senkronizasyon arayüzleri oluşturmak için çok düşük seviyeli bir yapı taşı olarak kullanılabilir. schedule(task) çağrısının kritik bir ön koşulu, çağrının task'ı "sahiplenmesi" gerektiğidir; yani, schedule(task) çağrısını yapan kodun, verilen task içindeki wait çağrısının nerelerde gerçekleştiğini bilmesi gerekir. Bu tür bir ön koşulu sağlamak için bir strateji, aşağıdaki örnekte gösterildiği gibi atomikler kullanmaktır:

@enum OWEState begin
    OWE_EMPTY
    OWE_WAITING
    OWE_NOTIFYING
end

mutable struct OneWayEvent
    @atomic state::OWEState
    task::Task
    OneWayEvent() = new(OWE_EMPTY)
end

function Base.notify(ev::OneWayEvent)
    state = @atomic ev.state
    while state !== OWE_NOTIFYING
        # Spin until we successfully update the state to OWE_NOTIFYING:
        state, ok = @atomicreplace(ev.state, state => OWE_NOTIFYING)
        if ok
            if state == OWE_WAITING
                # OWE_WAITING -> OWE_NOTIFYING transition means that the waiter task is
                # already waiting or about to call `wait`. The notifier task must wake up
                # the waiter task.
                schedule(ev.task)
            else
                @assert state == OWE_EMPTY
                # Since we are assuming that there is only one notifier task (for
                # simplicity), we know that the other possible case here is OWE_EMPTY.
                # We do not need to do anything because we know that the waiter task has
                # not called `wait(ev::OneWayEvent)` yet.
            end
            break
        end
    end
    return
end

function Base.wait(ev::OneWayEvent)
    ev.task = current_task()
    state, ok = @atomicreplace(ev.state, OWE_EMPTY => OWE_WAITING)
    if ok
        # OWE_EMPTY -> OWE_WAITING transition means that the notifier task is guaranteed to
        # invoke OWE_WAITING -> OWE_NOTIFYING transition.  The waiter task must call
        # `wait()` immediately.  In particular, it MUST NOT invoke any function that may
        # yield to the scheduler at this point in code.
        wait()
    else
        @assert state == OWE_NOTIFYING
        # Otherwise, the `state` must have already been moved to OWE_NOTIFYING by the
        # notifier task.
    end
    return
end

ev = OneWayEvent()
@sync begin
    @async begin
        wait(ev)
        println("done")
    end
    println("notifying...")
    notify(ev)
end

# output
notifying...
done

OneWayEvent, bir görevin başka bir görevin notify'sini beklemesine izin verir. Bu, wait'in tek bir görevden yalnızca bir kez kullanılabileceği için sınırlı bir iletişim arayüzüdür (not: ev.task'ın atomik olmayan ataması).

Bu örnekte, notify(ev::OneWayEvent) yalnızca o OWE_WAITING durumunu OWE_NOTIFYING durumuna değiştiriyorsa schedule(ev.task) çağrısına izin verilir. Bu, wait(ev::OneWayEvent) işlemini gerçekleştiren görevin artık ok dalında olduğunu ve @atomicreplace(ev.state, state => OWE_NOTIFYING) işleminin başarısız olacağı için schedule(ev.task) çağrısında bulunan başka görevlerin olamayacağını bilmemizi sağlar.