Lợi thế của việc sử dụng async với MVC5 là gì?


120

Sự khác biệt giữa:

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = IdentityManager.Authentication.CheckPasswordAndSignIn(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

và:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
        if (result.Success)
        {
            return Redirect("~/home");
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(model);
}

Tôi thấy rằng mã MVC bây giờ có async nhưng sự khác biệt là gì. Cái nào cho hiệu suất tốt hơn cái kia? Có dễ gỡ lỗi sự cố với cái này hơn cái kia không? Tôi có nên thực hiện thay đổi đối với các bộ điều khiển khác để ứng dụng của mình thêm Async không?


Trong hầu hết các tình huống không có lợi nghiêm trọng cho việc sử dụng async trong MVC, tuy nhiên có nhiều tiêu cực
Chris Marisic

1
@ChrisMarisic - Một trong những điều nghiêm trọng nhất: bạn không thể sử dụng ReaderWriterLock hoặc bất kỳ phần mềm đồng bộ hóa nguyên thủy nào khác (ngoại trừ Semaphore).
Hoàn toàn 19/1218

Câu trả lời:


170

Các hành động không đồng bộ chỉ hữu ích khi bạn đang thực hiện các hoạt động liên kết I / O chẳng hạn như cuộc gọi máy chủ từ xa. Lợi ích của lệnh gọi không đồng bộ là trong quá trình I / O hoạt động, không có luồng công nhân ASP.NET nào được sử dụng. Vì vậy, đây là cách ví dụ đầu tiên hoạt động:

  1. Khi một yêu cầu truy cập hành động, ASP.NET lấy một luồng từ nhóm luồng và bắt đầu thực thi nó.
  2. Các IdentityManager.Authentication.CheckPasswordAndSignInphương pháp được gọi. Đây là một cuộc gọi chặn -> trong toàn bộ cuộc gọi, chuỗi công nhân đang bị đe dọa.

Và đây là cách hoạt động của cuộc gọi thứ hai:

  1. Khi một yêu cầu truy cập hành động, ASP.NET lấy một luồng từ nhóm luồng và bắt đầu thực thi nó.
  2. Các IdentityManager.Authentication.CheckPasswordAndSignInAsyncđược gọi là trả về ngay lập tức. Một cổng hoàn thành I / O được đăng ký và luồng công nhân ASP.NET được giải phóng vào nhóm luồng.
  3. Sau đó khi hoạt động hoàn tất, cổng I / O Completion được báo hiệu, một luồng khác được rút ra từ nhóm luồng để kết thúc việc trả lại chế độ xem.

Như bạn có thể thấy trong trường hợp thứ hai, các luồng công nhân ASP.NET chỉ được sử dụng trong một khoảng thời gian ngắn. Điều này có nghĩa là có nhiều luồng hơn có sẵn trong nhóm để phục vụ các yêu cầu khác.

Vì vậy, để kết luận, chỉ sử dụng các hành động không đồng bộ khi bạn có một API không đồng bộ thực sự bên trong. Nếu bạn thực hiện một cuộc gọi chặn bên trong một hành động không đồng bộ, bạn đang giết chết toàn bộ lợi ích của nó.


Làm thế nào về đồng bộ hóa ngữ cảnh. Đây sẽ không phải là một chi phí cao mà bạn không muốn sử dụng các hành động không đồng bộ? "Chi phí của một phương thức không đồng bộ thực sự thực thi không đồng bộ hoàn toàn phụ thuộc vào việc nó có cần chuyển luồng bằng SynchronizationContext.Post hay không. Nếu có, chi phí sẽ bị chi phối bởi công tắc luồng mà nó thực hiện khi tiếp tục. Điều đó có nghĩa là SynchronizationContext hiện tại tạo ra một sự khác biệt lớn." (Không đồng bộ trong C # 5.0, 2012, Alex Davies)
annemartijn

1
@Darin Tại sao việc phát hành luồng chính lại quan trọng đến vậy? Chủ đề có giới hạn không?
Omtechguy

1
@Omtechguy giải pháp tốt hơn là chuyển các yêu cầu không phải ASP.NET sang CDN. CDN đơn giản chỉ sử dụng tên miền phụ và nhóm ứng dụng riêng biệt cho các tệp vật lý như javascript và hình ảnh của bạn. Hoặc bạn có thể sử dụng NgineX / Lighttpd / Apache cho các tập tin, hoặc bạn có thể sử dụng dịch vụ của bên thứ ba như Akamai (vua cho CDN nhưng hầu hết đắt tiền)
Chris Marisic

Tôi vẫn còn bối rối. Khi CheckPasswordAndSignInAsyncđược gọi, ASP.NET lấy một luồng khác từ nhóm luồng và bắt đầu thực thi nó, phải không? Nếu không, nó được checking password procedurethực thi ở đâu?
KevinBui

2

Thông thường, một yêu cầu HTTP sẽ được xử lý bởi một luồng duy nhất, xóa hoàn toàn luồng đó khỏi nhóm cho đến khi phản hồi được trả lại. Với TPL, bạn không bị ràng buộc bởi ràng buộc này. Bất kỳ yêu cầu nào đến bắt đầu một sự tiếp tục với mỗi đơn vị tính toán cần thiết để tính toán một phản hồi có thể thực thi trên bất kỳ luồng nào trong nhóm. Với mô hình này, bạn có thể xử lý nhiều yêu cầu đồng thời hơn so với ASP.Net tiêu chuẩn.

Nếu đó là một số nhiệm vụ mới sẽ được thực hiện, hay không, và liệu nó có nên được chờ đợi hay không. Luôn nghĩ về 70 ms đó, đó là khoảng. tối đa. thời gian mà bất kỳ cuộc gọi phương thức nào sẽ mất. Nếu nó dài hơn, thì giao diện người dùng của bạn có thể sẽ không cảm thấy phản hồi nhanh.


0

Trong các ứng dụng web nhận thấy một số lượng lớn các yêu cầu đồng thời khi khởi động hoặc có tải liên tục (trong đó đồng thời tăng đột ngột), việc thực hiện các lệnh gọi dịch vụ web này không đồng bộ sẽ làm tăng khả năng phản hồi của ứng dụng của bạn. Một yêu cầu không đồng bộ cần cùng một khoảng thời gian để xử lý như một yêu cầu đồng bộ. Ví dụ: nếu một yêu cầu thực hiện một cuộc gọi dịch vụ web cần hai giây để hoàn thành, thì yêu cầu sẽ mất hai giây cho dù nó được thực hiện đồng bộ hay không đồng bộ. Tuy nhiên, trong một cuộc gọi không đồng bộ, một luồng không bị chặn phản hồi các yêu cầu khác trong khi chờ yêu cầu đầu tiên hoàn thành. Do đó, yêu cầu không đồng bộ ngăn chặn việc xếp hàng yêu cầu và tăng trưởng nhóm luồng khi có nhiều yêu cầu đồng thời gọi các hoạt động chạy dài.


Nếu ứng dụng aspnet của bạn phần lớn bao gồm các cuộc gọi đến các máy chủ web khác, phần lớn bạn đang hoạt động như một 'cổng vào' / 'proxy' và async hữu ích cho mục đích đó.
Chris Marisic
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.