2009-02-28 31 views

Trả lời

50

Đây là một câu hỏi thú vị.

Lập trình không đồng bộ là một mô hình lập trình chủ yếu là luồng đơn, tức là "sau một chuỗi thực hiện liên tục".

Bạn tham khảo javascript, vì vậy hãy thảo luận về ngôn ngữ đó, trong môi trường của trình duyệt web. Một trình duyệt web chạy một luồng thực thi javascript trong mỗi cửa sổ, nó xử lý các sự kiện (như onclick = "someFunction()") và các kết nối mạng (chẳng hạn như các cuộc gọi xmlhttprequest).

<script> 
function performRequest() { 
    xmlhttp.open("GET", "someurl", true); 
    xmlhttp.onreadystatechange = function() { 
    if (xmlhttp.readyState == 4) { 
     alert(xmlhttp.responseText); 
    } 
    } 
    xmlhttp.send(sometext); 
} 
</script> 
<span onclick="performRequest()">perform request</span> 

(Đây là ví dụ không hoạt động để chỉ trình bày khái niệm).

Để làm mọi thứ theo cách không đồng bộ, chuỗi điều khiển có thứ được gọi là 'vòng lặp chính'. Vòng lặp chính trông giống như sau:

while (true) { 
    event = nextEvent(all_event_sources); 
    handler = findEventHandler(event); 
    handler(event); 
} 

Điều quan trọng cần lưu ý đây không phải là 'vòng lặp bận'. Đây là loại giống như một chủ đề ngủ, chờ đợi cho hoạt động xảy ra. Hoạt động có thể được nhập từ người dùng (Chuyển động chuột, Nút bấm, Nhập) hoặc nó có thể là hoạt động mạng (Phản hồi từ máy chủ).

Vì vậy, trong ví dụ trên,

  1. Khi người dùng nhấp vào nhịp, một sự kiện buttonClicked sẽ được tạo ra, findEventHandler() sẽ tìm thấy những sự kiện onclick trên thẻ span, và sau đó xử lý đó sẽ là được gọi với sự kiện này.
  2. Khi yêu cầu xmlhttp được tạo, nó được thêm vào danh sách nguồn sự kiện all_event_sources.
  3. Sau khi hàm performRequest() trả về, vòng lặp chính đang chờ ở bước tiếp theo() chờ đợi phản hồi. Tại thời điểm này không có gì 'chặn' các sự kiện tiếp tục được xử lý.
  4. Dữ liệu trở lại từ máy chủ từ xa, nextEvent() trả về sự kiện mạng, trình xử lý sự kiện được tìm thấy là phương thức onreadystatechange(), phương thức đó được gọi và hộp thoại alert() kích hoạt.

Cần lưu ý rằng alert() là hộp thoại chặn. Khi hộp thoại đó xuất hiện, không thể xử lý thêm sự kiện nào nữa. Đó là một lập dị của mô hình javascript của các trang web mà chúng tôi có một phương pháp sẵn sàng có sẵn mà sẽ chặn thực hiện thêm trong bối cảnh của trang đó.

+0

đề nghị chỉnh sửa câu trả lời "Thật đáng giá" khác với "nó đáng giá" mà tôi nghĩ là ý định của bạn. Chỉ để tránh nhầm lẫn cho độc giả – MadMurf

+0

@MadMurf: Tôi cũng nhận thấy điều đó .... và sửa nó. – mpen

+0

>> Lập trình không đồng bộ là một mô hình lập trình chủ yếu là luồng đơn << - Không cố gắng để trở thành người theo dõi ở đây, nhưng tôi không thấy câu này đúng như thế nào. Có lập trình không đồng bộ ngụ ý bất cứ điều gì về chủ đề, hãy để một mình so vs nhiều? – Lee

15

Mô hình Javascript là đơn luồng. Cuộc gọi không đồng bộ là không phải một chuỗi mới, mà là ngắt một chuỗi hiện có. Nó tương tự như ngắt trong hạt nhân.

Có ý nghĩa khi có cuộc gọi không đồng bộ với một chuỗi duy nhất. Đây là cách suy nghĩ về nó: Khi bạn gọi một hàm trong một chuỗi đơn, trạng thái của phương thức hiện tại được đẩy lên một ngăn xếp (tức là các biến cục bộ). Chương trình con được gọi và cuối cùng trả về, lúc đó trạng thái ban đầu được bật ra khỏi ngăn xếp.

Với gọi lại không đồng bộ, điều tương tự cũng xảy ra! Sự khác biệt là chương trình con được gọi bởi hệ thống, không phải bởi mã hiện tại gọi một chương trình con.

+1

>> Cuộc gọi không đồng bộ không phải là chủ đề mới << - Tôi nghĩ đây là một tuyên bố gây hiểu lầm. Tôi không biết gì về việc ngăn JS thực hiện một yêu cầu XHR với các luồng mới. Tôi nghĩ rằng bạn có nghĩa là một chủ đề mới không được đảm bảo hoặc đề xuất bởi các đặc điểm kỹ thuật, nhưng chắc chắn có thể là cách nó được thực hiện bởi hệ thống. – Lee

4

Trong nhiều ứng dụng GUI, một cuộc gọi không đồng bộ (như invokeLater của Java) chỉ thêm đối tượng Runnable vào hàng đợi chuỗi GUI của nó. Chủ đề GUI đã được tạo và không tạo chuỗi mới. Nhưng các chủ đề thậm chí không cần thiết cho một hệ thống không đồng bộ. Lấy ví dụ, libevent, sử dụng select/poll/kqueue, v.v. để thực hiện các cuộc gọi không chặn tới các socket, sau đó kích hoạt callbacks cho mã của bạn, hoàn toàn không có chủ đề.

5

Một vài lưu ý về JavaScript nói riêng:

XMLHttpRequest s không bị chặn theo mặc định. Phương thức send() trả về ngay sau khi yêu cầu được chuyển tiếp đến ngăn xếp mạng bên dưới. Phản hồi từ máy chủ sẽ lên lịch cuộc gọi lại của bạn trên vòng lặp sự kiện như được thảo luận bằng các câu trả lời tuyệt vời khác.

Điều này không yêu cầu chủ đề mới. API socket cơ bản có thể chọn, tương tự như java.nio.channels trong Java.

Có thể tạo đồng bộXMLHttpRequest đối tượng bằng cách chuyển false làm thông số thứ ba cho open(). Điều này sẽ khiến phương thức send() chặn cho đến khi nhận được phản hồi từ máy chủ, do đó đặt vòng lặp sự kiện ở mức độ trễ mạng và có khả năng treo trình duyệt cho đến khi hết thời gian chờ mạng. Đây là một Bad Thing ™.

Firefox 3.5 sẽ giới thiệu JavaScript đa luồng trung thực với lớp học Worker. Mã nền chạy trong môi trường hoàn toàn riêng biệt và giao tiếp với cửa sổ trình duyệt bằng cách lập lịch gọi lại trên vòng lặp sự kiện.

+0

khi bạn nói rằng 'Một phản hồi từ máy chủ sẽ lên lịch một lời gọi lại của bạn trên vòng lặp sự kiện', cái nào/chuỗi gì đặt một sự kiện trên vòng lặp sự kiện để gọi lại được gọi? – Yiling

+1

@Yiling Sự kiện này được tạo bởi một chuỗi I/O bên trong trình duyệt, không phải là một chuỗi thực thi JavaScript. – Matthew

2

Không, nhưng nhiều hơn một chuỗi sẽ được tham gia.

Cuộc gọi không đồng bộ có thể khởi chạy một chuỗi khác để thực hiện công việc hoặc có thể đăng tin nhắn vào hàng đợi trên chuỗi khác, đã chạy. Người gọi tiếp tục và callee gọi lại khi nó xử lý tin nhắn.

Nếu bạn muốn thực hiện cuộc gọi đồng bộ trong ngữ cảnh này, bạn cần đăng một tin nhắn và chủ động chờ cuộc gọi lại xảy ra.

Vì vậy, tóm lại: Nhiều hơn một chuỗi sẽ được tham gia, nhưng nó không nhất thiết phải tạo một chủ đề mới.

2

Tôi không biết về javascript, nhưng ví dụ trong thế giới Windows Forms, lời gọi không đồng bộ có thể được thực hiện mà không cần nhiều chuỗi. Điều này liên quan đến cách hoạt động của Windows Message Pump. Về cơ bản một ứng dụng Windows Forms thiết lập một hàng đợi thông điệp thông qua đó Windows đặt tin nhắn thông báo cho nó về các sự kiện. Ví dụ, nếu bạn di chuyển chuột, tin nhắn sẽ được đặt trên hàng đợi đó. Ứng dụng Windows Forms sẽ ở trong vòng lặp vô tận tiêu thụ tất cả các tin nhắn được ném vào đó. Theo những gì mỗi tin nhắn chứa nó sẽ di chuyển các cửa sổ xung quanh, sơn lại chúng hoặc thậm chí gọi các phương thức do người dùng định nghĩa, trong số những thứ khác. Các cuộc gọi đến các phương thức được xác định bởi các đại biểu. Khi ứng dụng tìm thấy một cá thể đại biểu trong hàng đợi, nó sẽ vui vẻ gọi phương thức được đại biểu gọi.Vì vậy, nếu bạn đang ở trong một phương pháp làm một cái gì đó và muốn đẻ trứng một số công việc không đồng bộ mà không tạo một chủ đề mới, tất cả những gì bạn phải làm là đặt một thể hiện ủy nhiệm vào hàng đợi, sử dụng phương thức Control.BeginInvoke. Bây giờ, điều này không thực sự đa luồng, nhưng nếu bạn ném những phần rất nhỏ của công việc vào hàng đợi, nó sẽ trông giống như đa luồng. Mặt khác, nếu bạn cho nó một phương thức tốn thời gian để thực thi, ứng dụng sẽ đóng băng cho đến khi phương thức được thực hiện, nó sẽ trông giống như một ứng dụng bị kẹt, mặc dù nó đang làm gì đó.

Các vấn đề liên quan