繁体   English   中英

有一个无尽的工人线程的正确方法?

[英]Proper way to have an endless worker thread?

我有一个需要大量初始化的对象(在一台强壮的机器上1-2秒)。 虽然一旦初始化,只需要大约20毫秒来做一个典型的“工作”

为了防止每次应用程序想要使用它时重新初始化它(可能是每秒50次,或者在典型使用中几分钟都没有),我决定给它一个工作,并让它运行在它自己的线程上,检查在que中是否有任何工作。 但是,我不完全确定如何创建一个无论是否有工作运行的线程。

这就是我到目前为止所做的任何批评都受到欢迎

    private void DoWork()
    {
        while (true)
        {
            if (JobQue.Count > 0)
            {
                // do work on JobQue.Dequeue()
            }
            else
            {
                System.Threading.Thread.Sleep(50);
            }
        }
    }

经过深思熟虑:我以为我可能需要优先杀死这个线程让它永远运行,所以我想我会添加一个告诉线程结束的Job类型。 关于如何结束这样的线程的任何想法也赞赏。

无论如何你需要 lock ,所以你可以WaitPulse

while(true) {
    SomeType item;
    lock(queue) {
        while(queue.Count == 0) {
            Monitor.Wait(queue); // releases lock, waits for a Pulse,
                                 // and re-acquires the lock
        }
        item = queue.Dequeue(); // we have the lock, and there's data
    }
    // process item **outside** of the lock
}

添加像:

lock(queue) {
    queue.Enqueue(item);
    // if the queue was empty, the worker may be waiting - wake it up
    if(queue.Count == 1) { Monitor.PulseAll(queue); }
}

您可能还想查看这个问题 ,这会限制队列的大小(如果它太满则会阻塞)。

您需要一个同步原语,如WaitHandle (查看静态方法)。 通过这种方式,您可以“发出信号”工作线程有效。 它会检查队列并继续工作,直到队列为空,此时它会等待互斥锁再次发出信号。

使其中一个作业项也是一个退出命令,这样你可以在退出线程时发出工作线程的信号

在大多数情况下,我这样做与您的设置非常相似 - 但不是使用相同的语言。 我有一个使用数据结构(在Python中)的优势,它将阻塞线程直到项目被放入队列,从而无需进行睡眠调用。

如果.NET提供了类似的类,我会考虑使用它。 线程阻塞比在睡眠调用上旋转的线程要好得多。

你可以传递的工作可以像“null”一样简单; 如果代码收到一个null,它知道是时候突破并回家了。

抓住并行框架 它有一个BlockingCollection <T> ,您可以将其用作作业队列。 你如何使用它是:

  1. 创建将保存任务/作业的BlockingCollection <T>。
  2. 创建一些具有永无止境循环的线程(while(true){//从队列中获取作业)
  3. 设置线程
  4. 当作业可用时,将作业添加到集合中

线程将被阻塞,直到项目出现在集合中。 无论谁转过它都会得到它(取决于CPU)。 我现在正在使用它,效果很好。

它还具有依赖于MS来编写特别讨厌的代码的优点,其中多个线程访问相同的资源。 无论什么时候你都可以让其他人写下你应该去的。 当然,假设他们拥有比您更多的技术/测试资源和综合经验。

如果你真的不需要让线程退出(并且只是希望它不让你的应用程序继续运行),你可以将Thread.IsBackground设置为true,它将在所有非后台线程结束时结束。 Will和Marc都有很好的解决方案来处理队列。

我已经实现了一个后台任务队列,而不使用任何类型的while循环,或者脉冲,或者等待,或者实际上完全触及Thread对象。 它似乎工作。 (我的意思是它在生产环境中处理了过去18个月中每天数千个任务而没有任何意外行为。)这是一个具有两个重要属性的类, Queue<Task>BackgroundWorker 有三种重要方法,缩写如下:

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
   if (TaskQueue.Count > 0)
   {
      TaskQueue[0].Execute();
   }
}

private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Task t = TaskQueue[0];

    lock (TaskQueue)
    {
        TaskQueue.Remove(t);
    }
    if (TaskQueue.Count > 0 && !BackgroundWorker.IsBusy)
    {
        BackgroundWorker.RunWorkerAsync();
    }
}

public void Enqueue(Task t)
{
   lock (TaskQueue)
   {
      TaskQueue.Add(t);
   }
   if (!BackgroundWorker.IsBusy)
   {
      BackgroundWorker.RunWorkerAsync();
   }
}

并不是没有等待和脉动。 但这一切都发生在BackgroundWorker 只要在队列中删除任务,运行直到队列为空,然后返回休眠状态,这就会唤醒。

我不是线程专家。 如果使用BackgroundWorker会有这样的问题,是否有理由搞乱System.Threading

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM