JavaScript'te Mutekslere ihtiyaç var mı?


104

Bu bağlantıyı gördüm: JavaScript'te Karşılıklı Dışlama Uygulamak . Öte yandan, javascript'te konu olmadığını okudum, ama bu tam olarak ne anlama geliyor?

Olaylar meydana geldiğinde, kodun neresinde kesintiye uğrayabilirler?

Ve JS'de hiç evre yoksa, JS'de muteks kullanmam gerekir mi, kullanmam gerekir mi?

Özellikle, setTimeout()ve XmlHttpRequest's tarafından çağrılan işlevleri kullanmanın onreadystatechangegenel olarak erişilebilir değişkenler üzerindeki etkilerini merak ediyorum .


1
Hayır, javascript'te muteks veya başka bir eşzamanlılık kontrol aracı yoktur. JavaScript'te neden eşzamanlılık kontrol aracı yok konusuna bakın .
Uzair Farooq

Yanıtlar:


101

Javascript bir evresel dil olarak tanımlanır, bu da kullanıcıya açık bir iş parçacığı olmadığı anlamına gelir, uygulamada iş parçacıkları olabilir. setTimeout()Eşzamansız geri çağırmalar gibi işlevlerin , çalıştırılmadan önce komut dosyası motorunun uyumasını beklemesi gerekir.

Bu, bir olayda olan her şeyin bir sonraki olay işlenmeden önce bitirilmesi gerektiği anlamına gelir.

Bununla birlikte, kodunuz eşzamansız olayın tetiklendiği zaman ile geri aramanın çağrıldığı zaman arasında bir değerin değişmemesini beklediği bir şey yapıyorsa bir mutekse ihtiyacınız olabilir.

Örneğin, bir düğmeyi tıkladığınız bir veri yapınız varsa ve veri yapısını yıkıcı bir şekilde değiştiren bir geri aramayı çağıran bir XmlHttpRequest gönderiyor ve aynı veri yapısını, olayın gerçekleştiği zaman arasında doğrudan değiştiren başka bir düğmeniz varsa başlatıldı ve geri arama yürütüldüğünde, kullanıcı geri aramadan önce veri yapısını tıklayıp güncelleyebilir ve bu durumda değeri kaybedebilir.

Böyle bir yarış koşulu oluşturabilirken, kodunuzda bunu önlemek çok kolaydır çünkü her işlev atomik olacaktır. Aslında yarış koşulunu oluşturmak için çok çalışma ve bazı garip kodlama kalıpları gerekir.


14
Bu yarış koşulunu yaratmak hiç de zor değil: örneğin, bir alanda bazı değerleri almak için bir DB'ye ajax çağrısını tetikleyen bir "onkeyup" olayım var. Verileri hızlı bir şekilde yazmak, kolayca sıra dışı sonuçlara yol açabilir.
thomasb

19

Bu soruya verilen cevaplar, verildikleri anda doğru olsa da biraz modası geçmiş cevaplardır. Web çalışanlarını KULLANMAYAN istemci tarafı bir javascript uygulamasına bakarsanız yine de doğru.

Web çalışanları ile ilgili makaleler: web çalışanları
kullanarak javascript'te çoklu okuma
Mozilla okuma

Bu, web çalışanları aracılığıyla javascript'in çoklu okuma yeteneklerine sahip olduğunu açıkça göstermektedir. Soru ile ilgili olarak javascript'te mutekslere ihtiyaç var mı? Bundan emin değilim. Ancak bu yığın aşımı gönderisi alakalı görünüyor:
N Eşzamansız İş Parçacığı için Karşılıklı Dışlama


3
geçmişten gelen patlama, ancak birden fazla sekme aynı yerel depolamaya eriştiğinde mutekslere ihtiyaç duydum
psp

3
WebWorkers yeniden giriş yapmayı etkilemez çünkü değişken bir durumu paylaşmazlar ve yalnızca olayları tetikleyen mesajları ileterek ana iş parçacığı ile iletişim kurarlar.
Alnitak

9

@William'ın işaret ettiği gibi,

Kodunuz, eşzamansız olayın tetiklendiği ve geri aramanın çağrıldığı zaman arasında bir değerin değişmemesini beklediği bir şey yapıyorsa bir mutekse ihtiyacınız olabilir.

Bu daha da genelleştirilebilir - eğer kodunuz, eşzamansız bir istek çözülene kadar bir kaynağın özel denetimini beklediği bir şey yaparsa, bir mutekse ihtiyacınız olabilir.

Basit bir örnek, arka uçta bir kayıt oluşturmak için bir ajax çağrısı başlatan bir düğmenizin olduğu yerdir. Sizi mutlu kullanıcıları tetiklemekten ve böylece birden fazla kayıt oluşturmaktan korumak için biraz koda ihtiyacınız olabilir. bu soruna birkaç yaklaşım vardır (örn. düğmeyi devre dışı bırakma, ajax başarısını etkinleştirme). Ayrıca basit bir kilit de kullanabilirsiniz:

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

Bunun en iyi yaklaşım olup olmadığından emin değilim ve başkalarının javascript'te karşılıklı dışlamayı nasıl ele aldığını görmek isterim, ama bildiğim kadarıyla bu basit bir muteks ve kullanışlı.


4
Bunu muteks olarak adlandırmam, en azından geleneksel anlamda değil, çünkü herhangi bir zamanda tek bir blok bağlamında çalışan iki iş parçacığına sahip değilsiniz.
Ovesh

10
muteks, basitçe 'ortak bir kaynağın eşzamanlı kullanımından kaçınmaya' yardımcı olan bir algoritmadır. Çok iş parçacıklı okuma, muteksler için bir ihtiyaç yaratsa da, tanımda muteksin tanımladığınız duruma özgü olduğunu söyleyen hiçbir şey yoktur.
alzclarke

1
Muteksin resmi tanımı konusunda haklısınız. Ancak, gerçek dünyadaki muteksler hakkında konuştuklarında insanların düşündükleri pek de bu değil.
Ovesh

Bu beklendiği gibi çalışmıyor. Ne yazık ki, tekrarlanan tıklamalar yine de ajax çağrısını ateşleyecektir. Başka bir fikrin var mı?
Muhammed Shareef C

1
Yeniden denemek ve zaman aşımı mantığına sahip olmak için, bunun n hatadan sonra bir whileile setTimeoutveya bir setIntervalile sarılması gerektiğinden oldukça eminim clearInterval. Olduğu gibi bırakmak, kilitli olan kodu atlayacağınız anlamına gelir. Muteksler ve paylaşılan nesnelerle harici işlem, uygulamaların kendisi kadar önemlidir.
MrMesees

6

JavaScript tek iş parçacıklı ... ancak Chrome yeni bir canavar olabilir (bence o da tek iş parçacıklı, ancak her sekmenin kendi JavaScript dizisi var ... Ona ayrıntılı olarak bakmadım, bu yüzden bana alıntı yapma Orada).

Ancak, endişelenmeniz gereken bir şey, JavaScript'inizin gönderdiğiniz sırayla geri dönen birden çok ajax isteğini nasıl işleyeceğidir. Bu nedenle, gerçekten endişelenmeniz gereken tek şey, ajax çağrılarınızın, sonuçlar sizin gönderdiğinizden farklı bir sırada gelirse birbirlerinin ayaklarına basmayacak şekilde ele alınmasını sağlamaktır.

Bu, zaman aşımları için de geçerli ...

JavaScript multithreading'i geliştirdiğinde, o zaman belki muteksler ve benzerleri hakkında endişelenebilirsiniz ...


4

Evet, localStorage gibi sekmeler / pencereler arasında paylaşılan kaynaklara erişirken Javascript'te muteksler gerekli olabilir .

Örneğin, bir kullanıcının açık iki sekmesi varsa, aşağıdaki gibi basit bir kod güvenli değildir:

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

LocalStorage öğesinin "aldı" ve "ayarlandı" olduğu zaman arasında, başka bir sekme değeri değiştirmiş olabilir. Genelde olası değildir, ancak mümkündür - kendi özel koşullarınızdaki herhangi bir ihtilafla ilişkili olasılığı ve riski kendiniz yargılamanız gerekir.

Daha fazla ayrıntı için aşağıdaki makalelere bakın:


2

JavaScript, dil olan istediğiniz kadar çok iş parçacıklı olabilir, ancak javascript motorunun tarayıcı yerleştirmeleri bir seferde yalnızca bir geri arama (onload, onfocus, <script>, vb.) Çalıştırır (sekme başına, muhtemelen). William'ın bir geri aramayı kaydetme ve alma arasındaki değişiklikler için bir Mutex kullanma önerisi, bu nedenle tam anlamıyla alınmamalıdır, çünkü kilidini açacak geri arama mevcut geri aramanın arkasında engelleneceğinden, araya giren geri aramayı engellemek istemeyeceksiniz. ! (Vay canına, İngilizce, iş parçacığı hakkında konuşmak için berbat.) Bu durumda, eğer bir bayrak ayarlandıysa, ya kelimenin tam anlamıyla ya da setTimeout () gibi, mevcut olayı yeniden göndermek için muhtemelen bir şeyler yapmak istersiniz.

Farklı bir JS gömme kullanıyorsanız ve bu aynı anda birden fazla iş parçacığı çalıştırıyorsa, biraz daha riskli olabilir, ancak JS'nin geri aramaları bu kadar kolay kullanabilmesi ve nesneleri mülk erişiminde kilitlemesi nedeniyle, açık kilitleme neredeyse gerekli değildir . Bununla birlikte, çoklu iş parçacığı kullanan genel kod için tasarlanmış bir gömme (örneğin, oyun komut dosyası oluşturma) aynı zamanda bazı açık kilitleme ilkelleri de vermezse şaşırırdım.

Metin duvarı için üzgünüm!


0

Olaylar bildirilir, ancak JavaScript yürütmesi hala tek iş parçacıklıdır.

Anladığım kadarıyla, olay sinyal verildiğinde motor olay işleyiciyi çalıştırmak için o anda yürütmekte olduğu şeyi durdurur. İşleyici bittikten sonra, komut dosyası yürütmeye devam edilir. Olay işleyici bazı paylaşılan değişkenleri değiştirdiyse, devam ettirilen kod bu değişikliklerin "birdenbire" göründüğünü görecektir.

Paylaşılan verileri "korumak" istiyorsanız, basit boole bayrağı yeterli olmalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.