【问题标题】:Task.Factory.StartNew() return thread to thread pool [duplicate]Task.Factory.StartNew()将线程返回到线程池[重复]
【发布时间】:2018-04-06 19:06:55
【问题描述】:

在这个实现中,Task.Factory.StartNew 永远不会将线程返回到线程池,因为它包含带有 Thread.Sleep 的 while(true)。这样对吗?如何查看queue是否有任务需要完成?

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        Helper h = new Helper();
        PlayWithQueue s = new PlayWithQueue();
        s.AddToQueueForExecution(() => { h.Indicate(1); });
        s.AddToQueueForExecution(() => { h.Indicate(2); });
        s.AddToQueueForExecution(() => { h.Indicate(3); });
        s.AddToQueueForExecution(() => { h.Indicate(4); });
        s.AddToQueueForExecution(() => { h.Indicate(5); });
        s.AddToQueueForExecution(() => { h.Indicate(6); });

        Console.ReadKey();
    }
}
public class PlayWithQueue
{
    private readonly ConcurrentQueue<Action> queue = new ConcurrentQueue<Action>();

    public PlayWithQueue()
    {
        var task = Task.Factory.StartNew(ThreadProc);
    }

    public void AddToQueueForExecution(Action action)
    {
        queue.Enqueue(action);
    }
    private void ThreadProc()
    {
        while (true)
        {
            Action item;
            bool isSuccessfull = false;
            isSuccessfull = queue.TryDequeue(out item);
            if (isSuccessfull)
            {
                item();
            }
            System.Threading.Thread.Sleep(100);
        }
    }
}
public class Helper
{
    public void Indicate(int number)
    {
        Random rnd = new Random();
        int timeDelay = rnd.Next(1000, 5000);
        Console.WriteLine("Start" + number.ToString());
        System.Threading.Thread.Sleep(timeDelay);
        Console.WriteLine("End" + number.ToString() + " " + timeDelay.ToString());
    }
}
}

【问题讨论】:

  • 是的,你永远窃取了一个 ThreadPool 线程。 How to check queue that it has task that need to be done? 是什么意思?
  • @FCin,没有 while(true) 有什么更好的解决方案?
  • 如果你打算有一个像这样运行很长时间的线程,不要使用线程池,只需创建一个真正的Thread。将线程池用于这样的事情最终会引入额外的复杂性。
  • 如果你真的想正确地做到这一点,请查看“生产者/消费者模式”。
  • 您可以通过 await Task.Delay 避免保持线程,但仍有更好的方法可以做到这一点。

标签: c# multithreading task-parallel-library


【解决方案1】:

将您的 ThreadProc 方法更改为此。循环直到队列有一个项目。

private void ThreadProc()
    {
        Action item;
        while (queue.TryDequeue(out item))
        {
            item();
            System.Threading.Thread.Sleep(100);
        }
    }

【讨论】:

  • 这根本没有任何区别 - 线程仍然被永远阻塞。
  • queue.TryDequeue 方法会将项目填充到 out 参数(项目)中并从队列中删除项目。因此,在每次迭代中,队列中的任务数将递减。一旦所有任务出队,queue.Dequeue 方法将返回 false,因此它会退出 while 循环,线程将返回到线程池。
  • @Bond,你能解释一下它有什么不同吗?一旦所有项目都出队,while循环将被终止,执行将退出while,因此线程将被释放。
  • 是的,你是对的。我的意思是它与线程点没有区别。但是您的解决方案不正确-在原始代码中,您有一个永远不会结束的循环-它将消耗添加到队列中的所有项目。您只需消耗队列中所有currently 的项目并结束。
【解决方案2】:

好的,有一段时间没有写任何 C#了,但这里是你不能阻塞线程的方法

private async void ThreadProc()
    {
        while (true)
        {
            Action item;
            bool isSuccessfull = false;
            isSuccessfull = queue.TryDequeue(out item);
            if (isSuccessfull)
            {
                item();
            }
            await Task.Delay(300);
        }
    }

但也许如果我要实现它,我会直接在AddToQueueForExecution 中运行该操作,而不是在另一个线程上排队...如果您希望这是thread safe,即没有两个操作可以同时运行时间 - 只需使用锁。

【讨论】:

  • 我至少会考虑让这个返回 Task 而不是 void,并让它在需要时使用 CancellationToken 来干净地跳出循环。
猜你喜欢
  • 1970-01-01
  • 2018-04-16
  • 2023-03-12
  • 2014-03-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多