2014-06-12 14 views
5

Chúng tôi đang sử dụng Xamarin để viết mã # C với SQLite cho Android và iOS là gì. Tuy nhiên về cách sử dụng SQLite, tôi dường như có một sự hiểu lầm về khái niệm:việc sử dụng chính xác cho sqlite trên khóa hoặc async

What are the best practices for SQLite on Android?

Theo stackoverflow trả lời nó nói - một helper và một kết nối db. Sử dụng khóa xung quanh nó để đảm bảo chỉ có một luồng truy cập vào sqlite db bất cứ lúc nào.

Câu hỏi của tôi là - nếu đó là trường hợp - sử dụng cho async là gì?

Tôi cố gắng để sử dụng async với mã đồng bộ - và mã đã cho tôi biên dịch lỗi chính đáng để tránh sự bế tắc.
Why can't I use the 'await' operator within the body of a lock statement?

public async Task InsertAsync<T> (T item){ 
     lock (mutex) { 
      await asyncConnection.InsertAsync (item); 
     } 
    } 

    public async Task InsertOrUpdateAsync<T> (T item){ 
     lock (mutex) { 
      int count = await asyncConnection.UpdateAsync (item); 
      if (0 == count) { 
       await asyncConnection.InsertAsync (item); 
      } 
     } 
    } 

thất bại. Tuy nhiên - nếu tôi sẽ sử dụng khóa để đảm bảo tôi đang sử dụng một kết nối một thread tại một thời điểm như là một thực hành tốt nhất trong sqlite - tại sao có một thư viện sqlite async ở tất cả?

Và tại sao là một số chủ đề thúc đẩy việc sử dụng SQLite async trên web.

các thực hành tốt nhất thực sự cho sqlite trong iphone android và là gì? Chỉ cần sử dụng phiên bản đồng bộ hóa?

Trả lời

6

Có sự khác biệt lớn giữa đồng bộ vs không đồng bộđơn vs đồng thời và có tất cả 4 sự kết hợp của họ.

Trong đơn trường hợpkhông đồng bộ bạn truy cập vào DB sử dụng một chủ đề duy nhất tại hầu hết, nhưng nó không cần phải được các chủ đề tương tự trong suốt hoạt động, và khi bạn không cần một sợi (khi bạn đang đợi hoạt động IO hoàn tất) bạn không cần bất kỳ chủ đề nào cả.

Cách cơ bản nhất để giới hạn sử dụng async cho một thao tác tại một thời điểm là sử dụng SemaphoreSlim với initialCount = 1. Một cách đẹp hơn sẽ được sử dụng một AsyncLock (Building Async Coordination Primitives, Part 6: AsyncLock bởi Stephen Toub):

private readonly AsyncLock _lock = new AsyncLock(); 

public async Task InsertAsync<T> (T item) 
{ 
    using(await _lock.LockAsync()) 
    { 
     await asyncConnection.InsertAsync (item); 
    } 
} 

public async Task InsertOrUpdateAsync<T> (T item) 
{ 
    using(await _lock.LockAsync()) 
    { 
     if (0 == await asyncConnection.UpdateAsync (item)) 
     { 
      await asyncConnection.InsertAsync (item); 
     } 
    } 
} 

Lưu ý: My implementation of AsyncLock

+0

Sự khác biệt duy nhất tôi thấy là câu lệnh 'using'.Trong nội bộ nó sử dụng một 'AsyncSemaphore', mà thẳng thắn im không chắc chắn làm thế nào nó khác với một' SemaphoreSlim'. Có bất kỳ lợi ích nào khác không? –

+0

@YuvalItzchakov Trong triển khai của tôi, nó sử dụng 'SemaphoreSlim'. Lợi ích là bạn sử dụng những gì bạn cần, và những gì bạn cần là một ** phạm vi khóa async ** vì vậy bạn đóng gói tất cả các quyết định vào một lớp học. Điều đó khuyến khích tái sử dụng và làm giảm các lỗi như của bạn, nơi bạn bỏ bê để phát hành sempahore. – i3arnon

+0

Đó là sự khác biệt giữa việc sử dụng 'Monitor.Enter' và' Monitor.Exit' trực tiếp thay vì sử dụng 'khóa'. Trong khi bạn * có thể * làm điều đó, bạn * không nên *. – i3arnon

3

Thực tế là Cơ sở dữ liệu của bạn không chấp nhận nhiều truy cập (chèn, cập nhật, v.v.) không có nghĩa là chuỗi duy nhất đang làm việc chống lại nó phải làm như vậy bằng cách sử dụng chặn api.

Nếu bạn không phải làm chéo quá trình khóa, bạn có thể sử dụng SemaphoreSlim.WaitAsync thay vì Mutex của bạn bên trong phương pháp async của bạn để chờ đợi khóa asynchrnously:

private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(initialCount: 1); 

public async Task InsertAsync<T>(T item) 
{ 
    await semaphoreSlim.WaitAsync(); 
    try 
    { 
     await asyncConnection.InsertAsync(item); 
    } 
    finally 
    { 
     semaphoreSlim.Release(); 
    } 
} 

public async Task InsertOrUpdateAsync<T>(T item) 
{ 
    await semaphoreSlim.WaitAsync(); 
    try 
    {  
     int count = await asyncConnection.UpdateAsync(item); 
     if (0 == count) 
     { 
     await asyncConnection.InsertAsync(item); 
     } 
    } 
    finally 
    { 
     semaphoreSlim.Release(); 
    } 
} 
+0

gì nếu bạn cần làm chéo quá trình khoá? Trên Android, tôi có Dịch vụ Android cần phải ghi vào cơ sở dữ liệu và tôi muốn Dịch vụ Android chạy trong một quy trình riêng biệt. –

+0

@DonBox Mutexes là chủ đề, vì vậy bạn sẽ không có nhiều may mắn trong khu vực đó. Có lẽ http://stackoverflow.com/questions/23153155/named-mutex-with-await có thể cung cấp cho bạn một số ý tưởng. –

+0

Cảm ơn bạn. Điều đó cũng áp dụng cho Xamarin? –

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