2015-12-02 12 views
5

Tôi đang làm việc trên ứng dụng API Web kết nối với hệ thống phụ trợ qua API. Một thách thức khi làm việc với API là nó đòi hỏi một phiên làm việc từ xa để được duy trì được chia sẻ giữa tất cả các luồng/yêu cầu tới API Web. Phiên hết hạn sau mỗi vài giờ và cần được "làm mới" thông qua thông tin đăng nhập.Truy cập đa luồng .NET vào Phiên đăng nhập được chia sẻ

Một phiên bản đơn giản thực hiện hiện tại của tôi là dưới đây:

private static Object loginLock = new Object(); 

if(!Api.IsLoggedIn) 
{ 
    lock(loginLock) 
    { 
     if(!Api.IsLoggedIn) 
     { 
      Api.Login(); 
     } 
    } 
} 

// Do stuff with the API 

Dưới đồng thời tải cao, khi một tên đăng nhập là cần thiết, chủ đề được xếp chồng lên nhau tại khóa và được cho qua một lúc sau khi một thành công đăng nhập đang gây ra một nút cổ chai hiệu suất.

Những gì tôi đang tìm kiếm là cách chặn tất cả các chuỗi khi đăng nhập là bắt buộc, nhưng hãy để chúng hoàn thành khi đăng nhập thành công.

Có mô hình nào tốt hơn để giải quyết vấn đề này không? Googling dường như chỉ ra rằng ReaderWriterLockSlim hoặc Monitor Wait/Pulse/PulseAll có thể là ứng cử viên tốt hơn so với khóa tiêu chuẩn.

+0

Vì tò mò, điều gì sẽ xảy ra khi phiên hết hạn sau khi kiểm tra 'Api.IsLoggedIn' nhưng trước khi sử dụng Api thực tế? –

+0

Cuộc gọi API sẽ không thành công với lỗi "không có phiên hợp lệ", nhưng chúng tôi chưa thấy trường hợp đó (cho đến nay). – WayneC

+3

Chính xác thì vấn đề là gì? Yêu cầu xếp hàng dường như không thể tránh khỏi. Nhưng một khi phiên họp trở nên có sẵn, hàng đợi sẽ rõ ràng cực kỳ nhanh chóng. Giống như một triệu sợi mỗi giây hoặc lâu hơn. – usr

Trả lời

2

Đó là một vấn đề bất thường và tôi không biết bất cứ điều gì được xây dựng trong đó đặc biệt giải quyết vấn đề này. Hãy nhớ rằng tôi đã gõ nó trong vài phút, và vì vậy tôi chắc chắn sẽ khuyên bạn không nên sử dụng điều này cho đến khi nhiều người có cơ hội nhìn vào nó và chỉ ra những sai sót của nó, đây là những gì tôi nghĩ:

private Task _loginLock = null; 

public void DoLoggedInCheck() 
{ 
    if (!Api.IsLoggedIn) 
    { 
     var tcs = new TaskCompletionSource<int>(); 
     var tsk = tcs.Task; 
     var result = Interlocked.CompareExchange(ref _loginLock, tsk, null); 
     if (result == null) 
     { 
      if (!Api.IsLoggedIn) 
      { 
       Api.Login(); 
      } 
      Interlocked.Exchange(ref _loginLock, null); 
      tcs.SetResult(1); 
     } 
     else 
     { 
      result.Wait(); 
     } 
    } 
} 

Logic được rằng, trong số tất cả các chủ đề mà chỗ đó đăng nhập là cần thiết, tất cả họ đều cạnh tranh (thông qua CompareExchange) là một tình nguyện khắc phục vấn đề. Một trong số họ thắng và thực hiện nhiệm vụ, phần còn lại chỉ chờ người chiến thắng báo hiệu thành công của họ.

Vẫn còn một số lượng nhỏ phân biệt chủng tộc ở đây, nhưng nó hiếm khi xảy ra.

+0

'if (result == tsk)' điều này sẽ không bao giờ đúng, vì 'CompareExchange' trả về giá trị ban đầu của trường, và nó là một số nhiệm vụ khác hoặc' null' trong luồng đầu tiên. Và nếu một số chuỗi sẽ 'Exchange'' _loginLock' với 'null', tất cả những người khác trong trường hợp này sẽ có' null' với 'CompareExchange', do đó' result.Wait(); 'sẽ sụp đổ. – VMAtm

+0

"Vẫn còn một số lượng nhỏ của raciness ở đây" đó là cách thú vị của việc đưa mọi thứ. Raciness là nhị phân, nó có hoặc không. – Andrey

+0

Tôi sẽ sử dụng Lazy cho mục này thay vì nhiệm vụ. – usr

0

Nếu bạn muốn giải quyết nó chỉ bằng cách sử dụng công nhân chủ đề Tôi không thấy bất kỳ cách nào khác, có một phần quan trọng và đây là bản chất của phần quan trọng mà chỉ có 1 thread có thể vượt qua nó tại một thời điểm. Cách tiếp cận hoàn toàn khác sẽ được xử lý ủy nhiệm của phần quan trọng để tách thread. Tôi không chắc chắn rằng nó sẽ được performant hơn (có lẽ nó sẽ được nhiều chậm hơn) nhưng một khi Api được đăng nhập sẽ không có ách tắc giao thông.

 private static AutoResetEvent requestLogin = new AutoResetEvent(); 
     private static ManualResetEvent responseLogin = new ManualResetEvent(); 

     //Worker thread: 

     if(!Api.IsLoggedIn) 
     { 
      requestLogin.Set(); 
      responseLogin.WaitOne(); 
     } 

     //Login thread 

     requestLogin.WaitOne(); 
     if(!Api.IsLoggedIn) 
     { 
      Api.Login(); 
     } 
     responseLogin.Set(); 
Các vấn đề liên quan