何时应将任务视为“长期运行"? [英] When should a task be considered "long running"?

查看:47
本文介绍了何时应将任务视为“长期运行"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在处理任务时,经验法则似乎是线程池-通常由例如调用 Task.Run() Parallel.Invoke()-应该用于较短的操作.就长时间运行的操作而言,我们应该使用 TaskCreationOptions.LongRunning 标志,以据我所知,避免阻塞线程池队列,即将工作推到新的状态.创建线程.

When working with tasks, a rule of thumb appears to be that the thread pool - typically used by e.g. invoking Task.Run(), or Parallel.Invoke() - should be used for relatively short operations. When working with long running operations, we are supposed to use the TaskCreationOptions.LongRunning flag in order to - as far as I understand it - avoid clogging the thread pool queue, i.e. to push work to a newly-created thread.

但是长期运行操作到底是什么?时间长短是多少?在确定是否使用 LongRunning 时,除了预期的任务持续时间之外,还有其他因素需要考虑吗,例如预期的CPU从程序员的角度来看架构(频率,内核数...)还是试图立即运行的任务数?

But what exactly is a long running operation? How long is long, in terms of time? Are there other factors besides the expected task duration to be considered when deciding whether or not to use the LongRunning, like the anticipated CPU architecture (frequency, the number of cores, ...) or the number of tasks that will be attempted to be run at once from the programmer's perspective?

例如,假设我有500个任务要在专用应用程序中处理,每个任务需要10到20秒才能完成.我是否应该仅使用Task.Run(例如,循环执行)来启动所有500个任务,然后等待所有任务(也许以 LongRunning 的形式),同时保留默认的最大并发级别?再说一次,如果我在这种情况下设置 LongRunning ,与省略 LongRunning ?这是假设在等待这500个任务时,不会安排任何新任务执行.

For example, suppose I have 500 tasks to process in a dedicated application, each taking 10-20 seconds to complete. Should I just start all 500 tasks using Task.Run (e.g. in a loop) and then await them all, perhaps as LongRunning, while leaving the default max level of concurrency? Then again, if I set LongRunning in such case, wouldn't this create 500 new threads and actually cause a lot of overhead and higher memory usage (due to extra threads being allocated) as compared to omitting LongRunning? This is assuming that no new tasks will be scheduled for execution while these 500 are being awaited.

我猜想设置 LongRunning 的决定取决于给定时间间隔内对线程池的请求数量,而 LongRunning 仅应使用对于预计将比大多数线程池放置的任务花费更长时间的任务(根据定义,最多占所有任务的一小部分).换句话说,这似乎是一个排队和线程池利用率优化问题,应该通过测试逐个解决(如果有的话).我说得对吗?

I would guess that the decision to set LongRunning depends on the number of requests made to the thread pool in a given time interval, and that LongRunning should only be used for tasks that are expected to take significantly longer that the majority of the thread pool-placed tasks - by definition, at most a small percentage of all tasks. In other words, this appears to be a queuing and thread pool utilization optimization problem that should likely be solved case-by-case through testing, if at all. Am I correct?

推荐答案

这没关系.问题不在于时间,而在于代码在做什么.如果要执行异步I/O,则仅在各个请求之间的较短时间内使用线程.如果您正在执行CPU工作...那么好,您正在使用CPU.没有线程池不足",因为CPU已被充分利用.

It kind of doesn't matter. The problem isn't really about time, it's about what your code is doing. If you're doing asynchronous I/O, you're only using the thread for the short amount of time between individual requests. If you're doing CPU work... well, you're using the CPU. There's no "thread-pool starvation", because the CPUs are fully utilized.

真正的问题是当您执行使用CPU的阻塞工作时.在这种情况下,线程池不足会导致CPU使用不足-您说我需要CPU来完成我的工作",然后才真正不使用它.

The real problem is when you're doing blocking work that doesn't use the CPU. In case like that, thread-pool starvation leads to CPU-underutilization - you said "I need the CPU for my work" and then you don't actually use it.

如果您没有使用阻止API,则将 Task.Run LongRunning 结合使用是没有意义的.如果必须异步运行一些旧版阻止代码,则使用 LongRunning 是个好主意.总工作时间不如您多久执行一次此操作"重要.如果您基于用户单击GUI来启动一个线程,则与首先单击按钮时已经包含的所有延迟相比,代价很小,您可以使用 LongRunning 可以避免线程池.如果您正在运行一个会产生大量阻塞任务的循环,请停止执行此操作.这是个坏主意:D

If you're not using blocking APIs, there's no point in using Task.Run with LongRunning. If you have to run some legacy blocking code asynchronously, using LongRunning may be a good idea. Total work time isn't as important as "how often you are doing this". If you spin up one thread based on a user clicking on a GUI, the cost is tiny compared to all the latencies already included in the act of clicking a button in the first place, and you can use LongRunning just fine to avoid the thread-pool. If you're running a loop that spawns lots of blocking tasks... stop doing that. It's a bad idea :D

例如,假设没有异步API替代品 File.Exists .因此,如果您发现这给您带来麻烦(例如,通过错误的网络连接),则可以使用 Task.Run 启动它-并且由于您没有进行CPU工作,因此您可以使用 LongRunning .

For example, imagine there is no asynchronous API alternative File.Exists. So if you see that this is giving you trouble (e.g. over a faulty network connection), you'd fire it up using Task.Run - and since you're not doing CPU work, you'd use LongRunning.

相反,如果您需要执行一些基本上需要100%CPU工作的图像处理,则操作所需的时间并不重要-这不是 LongRunning 事情.

In contrast, if you need to do some image manipulation that's basically 100% CPU work, it doesn't matter how long the operation takes - it's not a LongRunning thing.

最后,使用 LongRunning 的最常见情况是,当您的工作"实际上是老式的循环并定期检查是否应该执行某项操作,然后再循环".长时间运行,但99%的时间只是阻塞某些等待句柄之类的东西.同样,这仅在处理不受CPU限制但没有适当的异步API的代码时才有用.例如,如果您需要编写自己的 SynchronizationContext ,则可能会找到类似的内容.

And finally, the most common scenario for using LongRunning is when your "work" is actually the old-school "loop and periodically check if something should be done, do it and then loop again". Long running, but 99% of the time just blocking on some wait handle or something like that. Again, this is only useful when dealing with code that isn't CPU-bound, but that doesn't have proper asynchronous APIs. You might find something like this if you ever need to write your own SynchronizationContext, for example.

现在,我们如何将其应用于您的示例?好吧,我们不能没有更多的信息.如果您的代码是CPU绑定的,那么您需要的是 Parallel.For 和朋友-这些确保您仅使用足够的线程来提高CPU的性能,因此可以使用线程池.如果不是 CPU限制的话...如果要并行运行任务,除了使用 LongRunning 之外,您实际上没有任何其他选择.理想情况下,此类工作由异步调用组成,您可以安全地调用该异步调用,并从自己的线程中 await Task.WhenAll(...).

Now, how do we apply this to your example? Well, we can't, not without more information. If your code is CPU-bound, Parallel.For and friends are what you want - those ensure you only use enough threads to sature the CPUs, and it's fine to use the thread-pool for that. If it's not CPU bound... you don't really have any option besides using LongRunning if you want to run the tasks in parallel. Ideally, such work would consist of asynchronous calls you can safely invoke and await Task.WhenAll(...) from your own thread.

这篇关于何时应将任务视为“长期运行"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆