Có cần Mutexes trong javascript không?


104

Tôi đã thấy liên kết này: Triển khai Loại trừ lẫn nhau trong JavaScript . Mặt khác, tôi đã đọc rằng không có chủ đề nào trong javascript, nhưng chính xác thì điều đó có nghĩa là gì?

Khi các sự kiện xảy ra, chúng có thể ngắt ở đâu trong mã?

Và nếu không có luồng nào trong JS, tôi có cần sử dụng mutexes trong JS hay không?

Cụ thể, tôi đang thắc mắc về ảnh hưởng của việc sử dụng các hàm được gọi bởi setTimeout()XmlHttpRequest' onreadystatechangetrên các biến có thể truy cập toàn cục.


1
Không, không có mutex hoặc bất kỳ công cụ kiểm soát đồng thời nào khác trong javascript. Xem Tại sao không có công cụ kiểm soát đồng thời trong javascript .
Uzair Farooq,

Câu trả lời:


101

Javascript được định nghĩa là một ngôn ngữ reentrant có nghĩa là không có luồng nào được hiển thị cho người dùng, có thể có luồng trong quá trình triển khai. Các hàm như setTimeout()và lệnh gọi lại không đồng bộ cần phải đợi công cụ tập lệnh ngủ trước khi chúng có thể chạy.

Điều đó có nghĩa là mọi thứ xảy ra trong một sự kiện phải được hoàn thành trước khi sự kiện tiếp theo được xử lý.

Điều đó đang được nói, bạn có thể cần một mutex nếu mã của bạn thực hiện điều gì đó mà nó mong đợi giá trị không thay đổi giữa thời điểm sự kiện không đồng bộ được kích hoạt và khi lệnh gọi lại được gọi.

Ví dụ: nếu bạn có cấu trúc dữ liệu trong đó bạn nhấp vào một nút và nó sẽ gửi một XmlHttpRequest gọi một lệnh gọi lại, thay đổi cấu trúc dữ liệu theo cách phá hoại và bạn có một nút khác thay đổi trực tiếp cấu trúc dữ liệu tương tự, giữa thời điểm sự kiện xảy ra. được kích hoạt và khi lệnh gọi lại được thực thi, người dùng có thể đã nhấp và cập nhật cấu trúc dữ liệu trước lệnh gọi lại mà sau đó có thể mất giá trị.

Mặc dù bạn có thể tạo một điều kiện chủng tộc như vậy, nhưng rất dễ dàng để ngăn chặn điều đó trong mã của bạn vì mỗi hàm sẽ là nguyên tử. Sẽ là rất nhiều công việc và thực hiện một số mẫu mã kỳ quặc để tạo ra điều kiện cuộc đua trên thực tế.


13
Không khó chút nào để tạo ra điều kiện đua này: ví dụ: tôi có một sự kiện "onkeyup" trong một trường, sự kiện này sẽ kích hoạt một lệnh gọi ajax tới một DB để nhận một số giá trị. Nhập dữ liệu nhanh chóng có thể dễ dẫn đến kết quả không theo thứ tự.
thomasb 17/11/17

19

Các câu trả lời cho câu hỏi này hơi lỗi thời mặc dù đúng vào thời điểm chúng được đưa ra. Và vẫn đúng nếu nhìn vào ứng dụng javascript phía máy khách KHÔNG sử dụng webworkers.

Các bài viết trên web-
worker : multithreading trong javascript sử dụng webworkers
Mozilla trên webworkers

Điều này cho thấy rõ ràng rằng javascript thông qua web-worker có khả năng đa luồng. Liên quan đến câu hỏi có cần mutexes trong javascript không? Tôi không chắc về điều này. Nhưng bài đăng stackoverflow này có vẻ có liên quan:
Loại trừ lẫn nhau cho N chủ đề không đồng bộ


3
bùng nổ từ quá khứ, nhưng tôi gặp phải nhu cầu mutexes khi nhiều tab truy cập vào cùng một bộ nhớ cục bộ
psp

3
WebWorkers không ảnh hưởng đến sự hấp dẫn lại bởi vì họ không chia sẻ trạng thái thay đổi và chỉ giao tiếp với luồng chính bằng cách chuyển các thông báo, điều này sẽ kích hoạt các sự kiện.
Alnitak

9

Như @william đã chỉ ra,

bạn có thể cần một mutex nếu mã của bạn thực hiện điều gì đó mà nó mong đợi giá trị không thay đổi giữa thời điểm kích hoạt sự kiện không đồng bộ và khi lệnh gọi lại được gọi.

Điều này có thể được khái quát hóa thêm - nếu mã của bạn thực hiện điều gì đó mà nó mong đợi quyền kiểm soát độc quyền tài nguyên cho đến khi giải quyết được yêu cầu không đồng bộ, bạn có thể cần mutex.

Một ví dụ đơn giản là nơi bạn có một nút kích hoạt lệnh gọi ajax để tạo bản ghi ở phần cuối. Bạn có thể cần một chút mã để bảo vệ bạn khỏi việc kích hoạt người dùng vui vẻ nhấp chuột và do đó tạo nhiều bản ghi. có một số cách tiếp cận cho vấn đề này (ví dụ: vô hiệu hóa nút, bật ajax thành công). Bạn cũng có thể sử dụng một khóa đơn giản:

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

Tôi không chắc đó có phải là cách tiếp cận tốt nhất hay không và tôi muốn xem cách những người khác xử lý loại trừ lẫn nhau trong javascript, nhưng theo tôi biết thì đó là một mutex đơn giản và nó rất tiện dụng.


4
Tôi khó có thể gọi đây là mutex, ít nhất là không theo nghĩa truyền thống, bởi vì bạn không có hai luồng chạy trong ngữ cảnh của một khối duy nhất bất cứ lúc nào.
Ovesh

10
mutex chỉ đơn giản là một thuật toán giúp 'tránh việc sử dụng đồng thời tài nguyên chung'. Mặc dù đa luồng tạo ra nhu cầu về mutex, nhưng không có gì trong định nghĩa nói rằng mutex là cụ thể cho tình huống bạn mô tả.
alzclarke,

1
Bạn đã đúng về định nghĩa chính thức của mutex. Nhưng điều này hầu như không phải là những gì mọi người nghĩ đến khi họ nói về mutexes trong thế giới thực.
Ovesh

Điều này không hoạt động như mong đợi. Thật không may, các nhấp chuột lặp lại vẫn sẽ kích hoạt lệnh gọi ajax. Bất kỳ ý tưởng khác?
Mohammed Shareef C

1
Khá chắc chắn rằng điều này nên được gói trong một whilevới setTimeouthoặc một setIntervalclearIntervalsau n lần thất bại để bạn có logic thử lại và hết thời gian. Để nguyên nghĩa là bạn chỉ bỏ qua mã bị khóa. Việc xử lý bên ngoài với mutexes và các đối tượng được chia sẻ cũng quan trọng như chính việc triển khai.
MrMesees

6

JavaScript là một chuỗi đơn ... mặc dù Chrome có thể là một con thú mới (tôi nghĩ nó cũng là một chuỗi đơn, nhưng mỗi tab có một chuỗi JavaScript riêng ... Tôi chưa xem xét chi tiết về nó, vì vậy đừng trích dẫn tôi đó).

Tuy nhiên, một điều bạn CẦN lo lắng là cách JavaScript của bạn sẽ xử lý nhiều yêu cầu ajax quay trở lại không theo thứ tự bạn gửi chúng. Vì vậy, tất cả những gì bạn thực sự cần lo lắng là đảm bảo các cuộc gọi ajax của bạn được xử lý theo cách mà chúng sẽ không giẫm lên chân của người khác nếu kết quả trả về theo một thứ tự khác với bạn đã gửi.

Điều này cũng xảy ra với thời gian chờ ...

Khi JavaScript phát triển đa luồng, thì có thể lo lắng về mutexes và những thứ tương tự ...


4

Có, có thể yêu cầu mutexes trong Javascript khi truy cập các tài nguyên được chia sẻ giữa các tab / cửa sổ, như localStorage .

Ví dụ: nếu người dùng có hai tab đang mở, mã đơn giản như sau không an toàn:

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

Giữa thời điểm mục localStorage là 'got' và 'set', một tab khác có thể đã sửa đổi giá trị. Nói chung là khó xảy ra, nhưng có thể xảy ra - bạn cần tự đánh giá khả năng xảy ra và rủi ro liên quan đến bất kỳ tranh chấp nào trong các trường hợp cụ thể của bạn.

Xem các bài viết sau để biết thêm chi tiết:


2

JavaScript, ngôn ngữ , có thể đa luồng như bạn muốn, nhưng việc nhúng trình duyệt của công cụ javascript chỉ chạy một lệnh gọi lại (onload, onfocus, <script>, v.v.) tại một thời điểm (có lẽ là trên mỗi tab). Đề xuất của William về việc sử dụng Mutex cho các thay đổi giữa đăng ký và nhận cuộc gọi lại không nên hiểu theo nghĩa đen vì điều này, vì bạn sẽ không muốn chặn cuộc gọi lại can thiệp vì lệnh gọi lại sẽ mở khóa sẽ bị chặn phía sau lệnh gọi lại hiện tại ! (Chà, tiếng Anh thật tệ khi nói về phân luồng.) Trong trường hợp này, bạn có thể muốn làm điều gì đó dọc theo đường phân chia lại sự kiện hiện tại nếu một cờ được đặt, theo nghĩa đen hoặc tương tự như setTimeout ().

Nếu bạn đang sử dụng cách nhúng JS khác và thực thi nhiều luồng cùng một lúc, thì việc này có thể phức tạp hơn một chút, nhưng do cách JS có thể sử dụng lệnh gọi lại quá dễ dàng và việc khóa các đối tượng trên quyền truy cập thuộc tính, việc khóa rõ ràng là không cần thiết . Tuy nhiên, tôi sẽ ngạc nhiên nếu một bản nhúng được thiết kế cho mã chung (ví dụ: kịch bản trò chơi) sử dụng đa luồng cũng không cung cấp một số nguyên tắc khóa rõ ràng.

Xin lỗi cho bức tường của văn bản!


0

Các sự kiện được báo hiệu, nhưng việc thực thi JavaScript vẫn là một luồng.

Sự hiểu biết của tôi là khi sự kiện được báo hiệu, động cơ dừng những gì nó đang thực thi tại thời điểm này để chạy trình xử lý sự kiện. Sau khi trình xử lý kết thúc, quá trình thực thi tập lệnh được tiếp tục. Nếu trình xử lý sự kiện đã thay đổi một số biến được chia sẻ thì mã được tiếp tục lại sẽ thấy những thay đổi này xuất hiện "bất thường".

Nếu bạn muốn "bảo vệ" dữ liệu được chia sẻ, cờ boolean đơn giản là đủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.