我在Singleton类中有一个方法,它将从不同的线程调用。但我需要逐个执行它们。喜欢
将从多个线程调用ImageUtil.Instance.LoadImage(imageID)方法。但我想逐个加载图片。因此,一次只会加载一个图像。
public class ImageUtil
{
#region Singleton Implementation
private ImageUtil()
{
taskList = new List<Task<object>>();
}
public static ImageUtil Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as before field init
static Nested()
{
}
internal static readonly ImageUtil instance = new ImageUtil();
}
#endregion
Queue<Task<Object>> taskList;
bool isProcessing;
public async Task<Object> LoadImage(String imageID)
{
//Here what I need to put to execute "return await LoadImageInternal(imageID);"
//one by one. So that if one image is loading and mean time some other thread
//calls this method then the last thread have to wait until current loading finish.
}
private async Task<Object> LoadImageInternal(String imageID)
{
//Business Logic for image retrieval.
}
}
答案 0 :(得分:6)
SemaphoreSlim
有一个WaitAsync
方法,允许您异步执行关键部分:
private readonly SemaphoreSlim loadSemaphore = new SemaphoreSlim(1, 1);
public async Task<Object> LoadImage(String imageID)
{
await loadSemaphore.WaitAsync();
try
{
return await LoadImageInternal(imageID);
}
finally
{
loadSemaphore.Release();
}
}
此模式显示在Stephen Toub's article。
中答案 1 :(得分:0)
List<Task<Object>> taskList;
private static readonly object _syncLock = new object();
public Task<Object> LoadImage(String imageID)
{
return Task<Object>.Factory.StartNew(() =>
{
lock (_syncLock)
{
return LoadImageInternal(imageID).Result;
}
});
}
private async Task<Object> LoadImageInternal(String imageID)
{
//Business Logic for image retrieval.
}
那应该完成你要求的,但我个人会用一个长期运行的任务和某种Queue
来解决这个问题。长时间运行的任务将永远循环并检查队列中的新项目,然后一次执行一个,这将防止大量不必要的线程上下文切换。
答案 2 :(得分:0)
//This is how you can implement it using yield return to return one image at a time
public IEnumerable<Task<string>> GetPerItemAsync(IEnumerable<string> images)
{
foreach (var image in images)
{
yield return LoadImage(image);
}
}
public static Task<string> LoadImage(string image)
{
var result = image.Trim(); // Some complex business logic on the image, NOT
return new Task<string>(() => result);
}
//Call your method in you client
//First, get your images from the data source
var listOfimages = Context.Images.ToList();
//Get results
var result = GetPerItemAsync(listOfimages).FirstOrDefault();