Threads vs. Tasks
Posted on Friday, October 11, 2013
.Net has three low-level mechanisms to run code in parallel: Thread
, ThreadPool
, and Task
. These three mechanism serve different purposes.
Thread
Thread
represents an actual OS-level thread, with its own stack and kernel resources. (technically, a CLR implementation could use fibers instead, but no existing CLR does this) Thread
allows the highest degree of control; you can Abort()
or Suspend()
or Resume()
a thread (though this is a very bad idea), you can observe its state, and you can set thread-level properties like the stack size, apartment state, or culture.
The problem with Thread
is that OS threads are costly. Each thread you have consumes a non-trivial amount of memory for its stack, and adds additional CPU overhead as the processor context-switch between threads. Instead, it is better to have a small pool of threads execute your code as work becomes available.
There are times when there is no alternative Thread
. If you need to specify the name (for debugging purposes) or the apartment state (to show a UI), you must create your own Thread
(note that having multiple UI threads is generally a bad idea). Also, if you want to maintain an object that is owned by a single thread and can only be used by that thread, it is much easier to explicitly create a Thread
instance for it so you can easily check whether code trying to use it is running on the correct thread.
ThreadPool
ThreadPool
is a wrapper around a pool of threads maintained by the CLR. ThreadPool
gives you no control at all; you can submit work to execute at some point, and you can control the size of the pool, but you can't set anything else. You can't even tell when the pool will start running the work you submit to it.
Using ThreadPool
avoids the overhead of creating too many threads. However, if you submit too many long-running tasks to the threadpool, it can get full, and later work that you submit can end up waiting for the earlier long-running items to finish. In addition, the ThreadPool
offers no way to find out when a work item has been completed (unlike Thread.Join()
), nor a way to get the result. Therefore, ThreadPool
is best used for short operations where the caller does not need the result.
Task
Finally, the Task
class from the Task Parallel Library offers the best of both worlds. Like the ThreadPool
, a task does not create its own OS thread. Instead, tasks are executed by a TaskScheduler
; the default scheduler simply runs on the ThreadPool.
Unlike the ThreadPool, Task
also allows you to find out when it finishes, and (via the generic Task<T>
) to return a result. You can call ContinueWith()
on an existing Task
to make it run more code once the task finishes (if it's already finished, it will run the callback immediately). If the task is generic, ContinueWith()
will pass you the task's result, allowing you to run more code that uses it.
You can also synchronously wait for a task to finish by calling Wait()
(or, for a generic task, by getting the Result
property). Like Thread.Join()
, this will block the calling thread until the task finishes. Synchronously waiting for a task is usually bad idea; it prevents the calling thread from doing any other work, and can also lead to deadlocks if the task ends up waiting (even asynchronously) for the current thread.
Since tasks still run on the ThreadPool, they should not be used for long-running operations, since they can still fill up the thread pool and block new work. Instead, Task
provides a LongRunning
option, which will tell the TaskScheduler
to spin up a new thread rather than running on the ThreadPool.
All newer high-level concurrency APIs, including the Parallel.For*()
methods, PLINQ, C# 5 await
, and modern async methods in the BCL, are all built on Task
.
Conclusion
The bottom line is that Task
is almost always the best option; it provides a much more powerful API and avoids wasting OS threads.
The only reasons to explicitly create your own Thread
s in modern code are setting per-thread options, or maintaining a persistent thread that needs to maintain its own identity.
http://blog.slaks.net/2013-10-11/threads-vs-tasks/
Threads vs. Tasks的更多相关文章
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- Understanding the Internal Message Buffers of Storm
Understanding the Internal Message Buffers of Storm Jun 21st, 2013 Table of Contents Internal messag ...
- 进程物理内存远大于Xmx的问题分析
问题描述 最近经常被问到一个问题,”为什么我们系统进程占用的物理内存(Res/Rss)会远远大于设置的Xmx值”,比如Xmx设置1.7G,但是top看到的Res的值却达到了3.0G,随着进程的运行,R ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- ThreadPoolExecutor机制探索-我们到底能走多远系列(41)
我们到底能走多远系列(41) 扯淡: 这一年过的不匆忙,也颇多感受,成长的路上难免弯路,这个世界上没人关心你有没有变强,只有自己时刻提醒自己,不要忘记最初出发的原因. 其实这个世界上比我们聪明的人无数 ...
- 怎么通过activity里面的一个按钮跳转到另一个fragment(android FragmentTransaction.replace的用法介绍)
即:android FragmentTransaction.replace的用法介绍 Fragment的生命周期和它的宿主Activity密切相关,几乎和宿主Activity的生命周期一致,他们之间最 ...
- OpenMP初步(英文)
Beginning OpenMP OpenMP provides a straight-forward interface to write software that can use multipl ...
- ThreadPoolExecutor 分析
一.从用法入手 Creates a thread pool that creates new threads as needed, but will reuse previously construc ...
- Threading in C#
http://www.albahari.com/threading/ PART 1: GETTING STARTED Introduction and Concepts C# supports par ...
随机推荐
- 3682: Phorni 后缀平衡树 线段树
国际惯例的题面: 考虑如果没有强制在线我们能怎么水掉这个题,先构造出字符串,各种方法求一下后缀数组,然后线段树维护区间rank最小的位置即可.然而他要求强制在线,支持插入后缀,并比较后缀大小(求ran ...
- bzoj 3811: 玛里苟斯
3811: 玛里苟斯 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 190 Solved: 95[Submit][Status][Discuss] ...
- struts2标签在jsp页面中构建map集合,循环显示
<s:radio name="gender" list="{'男', '女'}"></s:radio> <s:select nam ...
- Linux下阅读MHT文件
Linux下阅读MHT文件 2016年02月04日 15:11:32 dj0379 阅读数:1769 mht是一种WEB电子邮件档案,用IE选择保存网页类型时可以看到有这一项,其最大优点是所保存的 ...
- 290.单词模式。给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式。(c++方法)
题目描述: 给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循相同的模式. 这里的遵循指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之 ...
- 奇怪吸引子---QiChen
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- eclipse-在编译项目时js特别慢的问题
eclipse在编译项目时,当项目中导入了很多第三方js库时,eclipse在验证js时会消耗大量的时间,而我们却完全不用考虑那些js是否有错误 步骤: 去除eclipse的JS验证: 1.将wind ...
- Idea调试
Idea调试 学习了:https://www.jb51.net/article/128965.htm 1,多线程同时断点: 2,drop frame 回退调试: 3,条件断点/片段代码: 4,调试的时 ...
- 微信小程序的同步操作
小程序里,大多数操作都是异步操作,一些重要的操作,如从网上获取重要变量值,必须要保证有值,后续操作才有意义.但异步操作,又必须把处理放到回调中,代码可读性降低,而且和大多数正常逻辑相背. 折腾了两天, ...
- Python中文语料批量预处理手记
手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...