C#中的同步任务执行
Synchronous Task Execution in C#
我在 Singleton class 中有一个方法,它将被不同的线程调用。但是我需要一个一个地执行它们。喜欢
方法 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.
}
}
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
来以不同的方式解决这个问题。长 运行 任务将永远循环并检查队列中是否有新项目,然后一次执行一个项目,这将防止大量不必要的线程上下文切换。
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。
//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();
我在 Singleton class 中有一个方法,它将被不同的线程调用。但是我需要一个一个地执行它们。喜欢
方法 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.
}
}
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
来以不同的方式解决这个问题。长 运行 任务将永远循环并检查队列中是否有新项目,然后一次执行一个项目,这将防止大量不必要的线程上下文切换。
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。
//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();