如果队列不为空而不使用 while(true) 是否可以执行代码?
Is it possible to execute codes if a queue is not empty without using while(true)?
现在或自从我学习编程以来,我正在使用以下代码来执行此操作:
ConcurrentQueue<MyPkg> messageQueue= new ConcurrentQueue<MyPkg>;
private void Post()
{
while (true)
{
if (messageQueue.IsEmpty)
{
//Post to server
}
Thread.Sleep(1);
}
}
这个 while-sleep "Query Mode" 看起来很愚蠢....大多数时候 cpu 只是保持上下文切换 nothing.But 很多人都在这样做。有没有更好的办法? "interrupt" 或 "trigger" 之类的方式?
有许多不同的方法可以解决您的问题。哪一个最好取决于你的情况。不可能在此处提供所有可能的选项,尤其是因为某些解决方案可能会变得相当复杂。最后是了解您的选择并将它们用作解决方案中的构建块。
这里有一些您可以做的事情。请注意,这些是非常基本的实现,没有考虑取消和超时。您必须根据您的要求将它们添加到组合中。
旋转等待
您可以使用 SpinWait
等到您的队列中有任何项目。 SpinWait
当您期望等待时间相当短时是一个不错的选择,因为在这些情况下它会自旋而不是导致线程上下文切换。 SpinWait
如果等待时间太长会自动锁定,但您仍然不应该使用它来等待更长的时间。
例如:
while (true)
{
while (!messageQueue.IsEmpty)
{
//Post to server
}
SpinWait.SpinUntil(() => !messageQueue.IsEmpty);
}
等待句柄
另一种选择是使用等待句柄,该句柄可以在项目排队时设置并阻塞接收线程。这通常会导致线程切换,因此当数据传入不是太频繁时,这是一个不错的选择,但处理非常昂贵,或者其他线程可能会更好地利用处理时间而队列中没有任何内容。
等待句柄的一个不错的选择是 AutoResetEvent
:
AutoResetEvent waitHandle = new AutoResetEvent(false);
while (true)
{
waitHandle.WaitOne();
while (!messageQueue.IsEmpty)
{
//Post to server
}
}
//When you enqueue your items...
messageQueue.Enqueue(item);
waitHandle.Set();
正在启动一个任务来处理队列
如果队列中的数据以短暂的突发形式出现,随后出现较长的中断,最好不要 运行 在无事可做时在后台进行任何操作,只启动一个将清空的任务队列中有项目时。在较长的休息时间,您可以 return 将处理队列的线程转移到线程池,在那里它可以用于更重要的事情。
您可以按需启动一个Task
,并使用一个bool
变量来跟踪您的处理任务是否运行ning。
bool isProcessing = false;
object processingSync = new object();
//...
void ProcessQueue()
{
bool shouldContinue;
do
{
object item; //Set thhis to the right type
lock (processingSync)
{
//Note: you wouldn't actually need a concurrent queue here,
//since you are locking during enqueue and dequeue
shouldContinue = messageQueue.TryDequeue(out item);
if (!shouldContinue)
{
isProcessing = false;
}
}
//Process item
}
while (shouldContinue);
}
//When you enqueue your items...
lock (processingSync)
{
messageQueue.Enqueue(item);
if (!isProcessing)
{
Task.Run(ProcessQueue);
isProcessing = true;
}
}
当您事先知道队列中有多少项目时,您也可以使用 BlockingCollection
,它的优点是您不必自己手动锁定。
现在或自从我学习编程以来,我正在使用以下代码来执行此操作:
ConcurrentQueue<MyPkg> messageQueue= new ConcurrentQueue<MyPkg>;
private void Post()
{
while (true)
{
if (messageQueue.IsEmpty)
{
//Post to server
}
Thread.Sleep(1);
}
}
这个 while-sleep "Query Mode" 看起来很愚蠢....大多数时候 cpu 只是保持上下文切换 nothing.But 很多人都在这样做。有没有更好的办法? "interrupt" 或 "trigger" 之类的方式?
有许多不同的方法可以解决您的问题。哪一个最好取决于你的情况。不可能在此处提供所有可能的选项,尤其是因为某些解决方案可能会变得相当复杂。最后是了解您的选择并将它们用作解决方案中的构建块。
这里有一些您可以做的事情。请注意,这些是非常基本的实现,没有考虑取消和超时。您必须根据您的要求将它们添加到组合中。
旋转等待
您可以使用 SpinWait
等到您的队列中有任何项目。 SpinWait
当您期望等待时间相当短时是一个不错的选择,因为在这些情况下它会自旋而不是导致线程上下文切换。 SpinWait
如果等待时间太长会自动锁定,但您仍然不应该使用它来等待更长的时间。
例如:
while (true)
{
while (!messageQueue.IsEmpty)
{
//Post to server
}
SpinWait.SpinUntil(() => !messageQueue.IsEmpty);
}
等待句柄
另一种选择是使用等待句柄,该句柄可以在项目排队时设置并阻塞接收线程。这通常会导致线程切换,因此当数据传入不是太频繁时,这是一个不错的选择,但处理非常昂贵,或者其他线程可能会更好地利用处理时间而队列中没有任何内容。
等待句柄的一个不错的选择是 AutoResetEvent
:
AutoResetEvent waitHandle = new AutoResetEvent(false);
while (true)
{
waitHandle.WaitOne();
while (!messageQueue.IsEmpty)
{
//Post to server
}
}
//When you enqueue your items...
messageQueue.Enqueue(item);
waitHandle.Set();
正在启动一个任务来处理队列
如果队列中的数据以短暂的突发形式出现,随后出现较长的中断,最好不要 运行 在无事可做时在后台进行任何操作,只启动一个将清空的任务队列中有项目时。在较长的休息时间,您可以 return 将处理队列的线程转移到线程池,在那里它可以用于更重要的事情。
您可以按需启动一个Task
,并使用一个bool
变量来跟踪您的处理任务是否运行ning。
bool isProcessing = false;
object processingSync = new object();
//...
void ProcessQueue()
{
bool shouldContinue;
do
{
object item; //Set thhis to the right type
lock (processingSync)
{
//Note: you wouldn't actually need a concurrent queue here,
//since you are locking during enqueue and dequeue
shouldContinue = messageQueue.TryDequeue(out item);
if (!shouldContinue)
{
isProcessing = false;
}
}
//Process item
}
while (shouldContinue);
}
//When you enqueue your items...
lock (processingSync)
{
messageQueue.Enqueue(item);
if (!isProcessing)
{
Task.Run(ProcessQueue);
isProcessing = true;
}
}
当您事先知道队列中有多少项目时,您也可以使用 BlockingCollection
,它的优点是您不必自己手动锁定。