C#-如何使用线程实现图像预加载缓存
在我的应用程序中,有一个图像列表,用户可以在其中单步执行。图像加载速度较慢,因此为了改善用户体验,我想在后台预加载一些图像(例如,列表中当前选定图像的后续图像) 我从来没有在C#中真正使用过线程,因此我正在寻找一些关于如何实现以下行为的“最佳实践”建议:C#-如何使用线程实现图像预加载缓存,c#,multithreading,C#,Multithreading,在我的应用程序中,有一个图像列表,用户可以在其中单步执行。图像加载速度较慢,因此为了改善用户体验,我想在后台预加载一些图像(例如,列表中当前选定图像的后续图像) 我从来没有在C#中真正使用过线程,因此我正在寻找一些关于如何实现以下行为的“最佳实践”建议: public Image LoadCachedImage(string path) { // check if the cache (being operated in the background) // has prelo
public Image LoadCachedImage(string path)
{
// check if the cache (being operated in the background)
// has preloaded the image
Image result = TryGetFromCache(path);
if (result == null) { result = LoadSynchronously(path); }
// somehow get a list of images that should be preloaded,
// e.g. the successors in the list
string[] candidates = GetCandidates(path);
// trigger loading of "candidates" in the background, so they will
// be in the cache when queried later
EnqueueForPreloading(candidates);
return result;
}
我认为,后台线程应该监视队列,并连续处理通过enqueueforpreload()发布的元素。我想知道如何实现后台工作线程的“主循环”(或者有更好的方法吗?如果确实需要对候选线程进行顺序处理,可以执行以下操作之一:
如果您不需要顺序处理,请考虑使用THEADPOLL。QueueUserWorkItem(…)。如果有空闲池线程,它将使用它们,否则它将对项目进行排队。但是你不能保证处理的顺序,有几个可能/将同时得到处理
下面是一个(有缺陷的)消息队列示例:class MyBackgroundQueue<T>
{
private Queue<T> _queue = new Queue<T>();
private System.Threading.AutoResetEvent _event = new System.Threading.AutoResetEvent(false);
private System.Threading.Thread _thread;
public void Start()
{
_thread = new System.Threading.Thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
public class ItemEventArgs : EventArgs
{ public T Item { get; set; } }
public event EventHandler<ItemEventArgs> ProcessItem;
private void ProcessQueueWorker()
{
while (true)
{
_event.WaitOne();
while (_queue.Count > 0)
ProcessItem(this, new ItemEventArgs { Item = _queue.Dequeue() });
}
}
public void Enqueue(T item)
{
_queue.Enqueue(item);
_event.Set();
}
}
类MyBackgroundQueue
{
专用队列_Queue=新队列();
private System.Threading.AutoResetEvent _event=new System.Threading.AutoResetEvent(false);
私有系统.Threading.Thread\u线程;
公开作废开始()
{
_thread=new System.Threading.thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
公共类ItemEventArgs:EventArgs
{public T Item{get;set;}}
公共事件事件处理程序ProcessItem;
私有void ProcessQueueWorker()
{
while(true)
{
_event.WaitOne();
而(_queue.Count>0)
ProcessItem(这是新的ItemEventArgs{Item=_queue.Dequeue()});
}
}
公共无效排队(T项)
{
_排队。排队(项目);
_event.Set();
}
}
当然,这里的一个缺陷是_队列未锁定,因此您将遇到竞争条件。但我会让您来解决这个问题(例如,使用2队列交换方法)。此外,while(true)永远不会中断,但我希望该示例符合您的目的。如果您确实需要对候选对象进行顺序处理,您可以执行以下操作之一:
如果您不需要顺序处理,请考虑使用THEADPOLL。QueueUserWorkItem(…)。如果有空闲池线程,它将使用它们,否则它将对项目进行排队。但是你不能保证处理的顺序,有几个可能/将同时得到处理
下面是一个(有缺陷的)消息队列示例:class MyBackgroundQueue<T>
{
private Queue<T> _queue = new Queue<T>();
private System.Threading.AutoResetEvent _event = new System.Threading.AutoResetEvent(false);
private System.Threading.Thread _thread;
public void Start()
{
_thread = new System.Threading.Thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
public class ItemEventArgs : EventArgs
{ public T Item { get; set; } }
public event EventHandler<ItemEventArgs> ProcessItem;
private void ProcessQueueWorker()
{
while (true)
{
_event.WaitOne();
while (_queue.Count > 0)
ProcessItem(this, new ItemEventArgs { Item = _queue.Dequeue() });
}
}
public void Enqueue(T item)
{
_queue.Enqueue(item);
_event.Set();
}
}
类MyBackgroundQueue
{
专用队列_Queue=新队列();
private System.Threading.AutoResetEvent _event=new System.Threading.AutoResetEvent(false);
私有系统.Threading.Thread\u线程;
公开作废开始()
{
_thread=new System.Threading.thread(new System.Threading.ThreadStart(ProcessQueueWorker));
_thread.Start();
}
公共类ItemEventArgs:EventArgs
{public T Item{get;set;}}
公共事件事件处理程序ProcessItem;
私有void ProcessQueueWorker()
{
while(true)
{
_event.WaitOne();
而(_queue.Count>0)
ProcessItem(这是新的ItemEventArgs{Item=_queue.Dequeue()});
}
}
公共无效排队(T项)
{
_排队。排队(项目);
_event.Set();
}
}
当然,这里的一个缺陷是_队列未锁定,因此您将遇到竞争条件。但我会让您来解决这个问题(例如,使用2队列交换方法)。另外,while(true)从不中断,但我希望该示例能够满足您的需要。这就是我所说的作弊缓存。操作系统已经为您缓存文件,但您必须先访问它们。因此,您可以只加载文件,而不保存对它们的引用 您可以在不使用多线程本身的情况下执行此操作,也不必将图像保存在列表中。只需为要在后台加载的每个文件创建一个方法委托和调用 例如,预加载目录中的所有jpeg图像
Action<string> d = (string file) => { System.Drawing.Image.FromFile(file); };
foreach(string file in dir.GetFiles("*.jpg"))
d.BeginInvoke(file);
Action d=(字符串文件)=>{System.Drawing.Image.FromFile(文件);};
foreach(dir.GetFiles(“*.jpg”)中的字符串文件)
d、 BeginInvoke(文件);
BeginInvoke()是一种多线程方法,循环速度非常快,但每个文件将加载到不同的线程上。或者你可以改变
Action<List<string>> d = PreCache;
d.BeginInvoke(theList);