当我不使用 TaskCreationOptions.LongRunning 时出现奇怪的行为

发布于 2024-10-22 05:03:29 字数 827 浏览 3 评论 0原文

我有一个引擎,它有任意数量的轮询器,每个轮询器每隔几秒进行一次“轮询”。我希望轮询器在不同的线程中运行,但单个轮询器中的每个“轮询”应该是连续的,以便一个轮询发生在下一个轮询之后。使用此代码启动轮询过程一切正常:

    public void StartPolling()
    {
        Stopwatch watch = new Stopwatch();
        while (Engine.IsRunning)
        {
            Task task = Task.Factory.StartNew(() =>{
                watch.Restart();
                Poll();
                watch.Stop();
            },TaskCreationOptions.LongRunning);
            task.Wait();
            if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
        }
    }

但是,我花了一段时间才发现 TaskCreationOptions.LongRunning 选项解决了我遇到的一个我仍然不明白的奇怪问题。 如果没有该选项,如果我运行创建 1-3 个轮询器的测试,则一切正常。如果我创建了 4+ 然后我会遇到奇怪的行为。三个轮询器可以工作,一个只能执行一项轮询,其余的则根本不会进行轮询。 我的任务是长期运行的,这是完全有道理的。毕竟他们正在运行我的程序的整个长度。但我不明白为什么如果没有设置此选项,我会出现一些不良行为。任何帮助将不胜感激。

I have an engine that has an arbitrary number of pollers which each do their "poll" every few seconds. I want the pollers to run in different threads, but each "poll" within a single poller should be sequential so that one happens after the next. Everything is working using this code to start the polling process:

    public void StartPolling()
    {
        Stopwatch watch = new Stopwatch();
        while (Engine.IsRunning)
        {
            Task task = Task.Factory.StartNew(() =>{
                watch.Restart();
                Poll();
                watch.Stop();
            },TaskCreationOptions.LongRunning);
            task.Wait();
            if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
        }
    }

It took me awhile, however, to discover the TaskCreationOptions.LongRunning option which solved a strange problem I was having that I still don't understand.
Without that option, if I run a test that creates 1-3 of these pollers, everything worked fine. If I created 4+ then I ran into strange behavior. Three of the pollers would work, one would just perform one poll, and any remaining would not poll at all.
It makes total sense that my tasks are long running. They are after all running the entire length of my program. But I don't understand why I would get some bad behavior without this option set. Any help would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

〆凄凉。 2024-10-29 05:03:29

当您不使用 LongRunning 标志时,任务将安排在线程池线程上,而不是其自己的(专用)线程上。这可能是导致您的行为发生变化的原因 - 当您在没有设置 LongRunning 标志的情况下运行时,您可能会由于进程中的其他线程而导致线程池匮乏。

话虽这么说,你上面的代码并没有多大意义。您正在启动一个专用线程(通过 Task....StartNew 和 LongRunning)来启动任务,然后立即调用 task.Wait(),这会阻塞当前线程。最好在当前线程中按顺序执行此操作:

public void StartPolling()
{
    Stopwatch watch = new Stopwatch();
    while (Engine.IsRunning)
    {
        watch.Restart();
        Poll();
        watch.Stop();
        if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
    }
}

When you don't use the LongRunning flag, the task is scheduled on a threadpool thread, not its own (dedicated) thread. This is likely the cause of your behavioral change - when you're running without the LongRunning flag in place, you're probably getting threadpool starvation due to other threads in your process.

That being said, your above code doesn't really make a lot of sense. You're starting a dedicated thread (via Task....StartNew with LongRunning) to start a task, then immediately calling task.Wait(), which blocks the current thread. It would be better to just do this sequentially in the current thread:

public void StartPolling()
{
    Stopwatch watch = new Stopwatch();
    while (Engine.IsRunning)
    {
        watch.Restart();
        Poll();
        watch.Stop();
        if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed);
    }
}
时光清浅 2024-10-29 05:03:29

TPL(和传统的ThreadPool)限制池中的线程数量(通常是CPU核心数量的一小部分,通常是2x核心)。如果您将任务标记为“LongRunning”,它就知道该任务不会很快完成,并且可能不会使该任务受到线程限制。

如果没有 LongRunning,它会假设您的任务将很快完成(但事实并非如此),因此它保持在线程限制内。然后,如果您创建的任务多于线程限制,并且正在运行的任务永远不会结束,TPL 会停止所有其他任务的运行,徒劳地等待这些正在运行的任务完成(它们永远不会这样做)。

TPL (and the traditional ThreadPool) limits the number of threads in the pool (typically a small multiple of the number of CPU cores, usually 2x cores). If you mark a task as LongRunning, it knows that the task won't finish soon and may not subject this task to the threads limit.

Without LongRunning, it assumes that you task will finish quickly (which it doesn't) so it stays within the threads limit. Then if you create more tasks than the threads limit and the running tasks never end, TPL stops all other tasks from running waiting in vain for those running tasks to finish (which they will never do).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文