Tôi đang cố gắng để chuyển đổi phương pháp sau đây (ví dụ đơn giản) là không đồng bộ, như cuộc gọi cacheMissResolver
có thể rất tốn kém về thời gian (tra cứu cơ sở dữ liệu, cuộc gọi mạng):Cách đúng để chuyển đổi phương thức thành không đồng bộ trong C#?
// Synchronous version
public class ThingCache
{
private static readonly object _lockObj;
// ... other stuff
public Thing Get(string key, Func<Thing> cacheMissResolver)
{
if (cache.Contains(key))
return cache[key];
Thing item;
lock(_lockObj)
{
if (cache.Contains(key))
return cache[key];
item = cacheMissResolver();
cache.Add(key, item);
}
return item;
}
}
Có rất nhiều vật liệu trên mạng về việc tiêu thụ các phương pháp không đồng bộ, nhưng lời khuyên tôi đã tìm thấy về việc sản xuất chúng dường như ít rõ ràng hơn. Vì đây là một phần của thư viện, một trong những nỗ lực của tôi dưới đây có đúng không?
// Asynchronous attempts
public class ThingCache
{
private static readonly SemaphoreSlim _lockObj = new SemaphoreSlim(1);
// ... other stuff
// attempt #1
public async Task<Thing> Get(string key, Func<Thing> cacheMissResolver)
{
if (cache.Contains(key))
return await Task.FromResult(cache[key]);
Thing item;
await _lockObj.WaitAsync();
try
{
if (cache.Contains(key))
return await Task.FromResult(cache[key]);
item = await Task.Run(cacheMissResolver).ConfigureAwait(false);
_cache.Add(key, item);
}
finally
{
_lockObj.Release();
}
return item;
}
// attempt #2
public async Task<Thing> Get(string key, Func<Task<Thing>> cacheMissResolver)
{
if (cache.Contains(key))
return await Task.FromResult(cache[key]);
Thing item;
await _lockObj.WaitAsync();
try
{
if (cache.Contains(key))
return await Task.FromResult(cache[key]);
item = await cacheMissResolver().ConfigureAwait(false);
_cache.Add(key, item);
}
finally
{
_lockObj.Release();
}
return item;
}
}
Có sử dụng đúng cách để thay thế tuyên bố khóa bằng phương pháp không đồng bộ không? (Tôi không thể chờ đợi trong nội dung của một tuyên bố khóa.)
Tôi có nên thực hiện đối số cacheMissResolver
loại Func<Task<Thing>>
thay thế không? Mặc dù điều này đặt gánh nặng của việc đảm bảo func giải quyết là không đồng bộ trên người gọi (gói trong Task.Run
, tôi biết nó sẽ được offloaded đến một chủ đề nền nếu phải mất một thời gian dài).
Cảm ơn.
Cân nhắc sử dụng ['AsyncLock'] (https://github.com/StephenCleary/AsyncEx/wiki/AsyncLock). –
'cache' là gì? – dbc
@Timothy Shields - Điều đó có vẻ hữu ích! Cảm ơn. – rob