线程,任务,线程池的学习总结

2023-11-03

同步操作(synchornous operation):先完成其工作再返回调用者。
异步操作(asynchornous operation):大部分工作是在返回给调用者之后才完成的,但是线程异步必须对资源进行协调,否则两个或者更多线程可能在同一时间访问相同的资源,二每个线程都不知道其他线程的操作,结果将产生不可预知的数据损坏。异步需要并发的创建,我们学习的异步方法通常有:Thread.Start和Task.Run还有Dispatcher.BeginInvoke,SynchronizationContext.Post。

富客户端应用程序的线程

在WPF,UWP,Windows Forms应用程序中,在主线程上执行长时间的操作将导致应用程序失去响应。一个常用的方法是创建一个工作线程来执行耗时的操作(通常用异步),并在完成之时更新UI线程,这种方法就要采用封送技术,实现这个操作的底层模式有:
1.WPF中,调用元素上的Dispatcher对象的BeginInvoke或者Invoke方法,这两者的区别看博客
2.在Windows Forms中:调用控件的BeginInvoke或者Invoke方法。
3.在UWP中:可以调用Dispatcher对象的RunAsync或者Invoke方法。
Invoke 或者 BeginInvoke 去调用,分别表示同步和异步,两者的区别就是一个导致工作线程等待,而另外一个则不会,线程同步时锁的使用可以参考这篇博客
UI线程也可以有多个,但每一个线程要对应不同的窗口。这样使每一个窗口指定独立的UI线程,可以让每一个窗口都具有更好独立响应的能力。

线程Thread

关于的Thread的使用可以看以前的博客点击这里
对线程的操作有创建,暂停(挂起),恢复,休眠和终止以及设置优先权。

这里讲述它的缺点:
1.线程完成后,就无法通过再次使用Start方法来重新启动它,相反只能将其Join(它告诉操作系统暂停执行当前线程,直到另一个线程终止)
2.直接使用线程会对性能产生影响,线程是昂贵的资源,上下文的切换不是免费的,如果需要运行大量并发的I/O密集型操作,线程本身的开销非常巨大。
3.线程除非创建共享字段,不然在Join之后难以得到“返回值”,此外捕获和处理线程中的操作抛出的异常也非常麻烦。

注意:如果线程里有while循环,会照成主界面卡顿

线程池

线程池是多个线程的集合,通过一定的逻辑决定如何为线程分配工作,有任务要执行时,它分配池中的一个工作者线程执行任务,线程池中的线程执行完指定的方法后并不会自动消除,而是以挂起状态返回线程池,如果应用程序再次向线程池发出请求,那么处以挂起状态的线程就会被激活并执行任务,而不会创建新线程,这就节约了很多开销。只有当线程数达到最大线程数量,任务会排队,等待其他任务释放线程后再执行。因此,使用线程池可以避免大量的创建和销毁的开支,具有更好的性能和稳定性,但是ThreadPool不能控制线程的执行顺序,我们不能有效监控和控制线程池中的线程。
所以它的效率是通过重用线程获得的。
但是线程池不包括需要长时间运行的工作。这种情况下使用任务并行库(Task Parallel Library,TPL),以后博客介绍。

public const int Repetition = 800;
        public  static void Main()
        {
            ThreadPool.QueueUserWorkItem(DoWork, '+');//将方法排入队列以便执行,并指定包含该方法所用数据的对象。 此方法在有线程池线程变得可用时执行。
            for (int count = 0; count < Repetition; count++)
            {
                Console.Write('-');
            }
        }
        public static void DoWork(object state)
        {
            for (int count = 0; count < Repetition; count++)
            {
                Console.Write(state);
            }
           
        }

注意:避免将线程池中的工作者线程分配给I/O受限(是从外部来源获取数据如磁盘驱动器,web服务器所产生的延迟)或长时间运行的任务,这时可以改用任务并行库(TPL)
需要注意:

  1. 线程池中的所有线程都是后台线程。如果进程的所有前台线程都结束了,所有的后台线程也都会停止。
  2. 不能将入池的线程改为前台线程。
  3. 不能给入池的线程设置优先级或名称。
  4. 入池的线程只能用于时间较短的任务。如果线程要一直运行(比如Word的拼写检查线程),就应该使用Thread类创建一个线程。

任务Task

Task类可以解决所有Thread的问题,通过Task“任务并行库”中的类轻松输入线程池
**任务是对象,其中封装了以异步方式执行的工作(委托也是封装了代码的对象,但是委托是同步的,而任务是异步的),所以不会阻塞线程。
以下实例描述任务如何获取一个Action并以异步方式
运行它

const int Rept = 800;
            Task task = Task.Run(()=>
            {
                for (int count = 0; count < Rept; count++)
                {
                    Console.Write('-');
                }
            });
            for(int count=0;count<Rept;count++)
            {
                Console.Write('+');
            }
            Task.Wait();//强迫主线程等待分配给任务的所有工作完成。相当于在工作者线程(自己创建的那个)上调用Join()

以下实例描述执行的任务返回结果

static void Main(string[] args)
{  
   Task<string> task2 = Task.Run<string>(() => TempClass.TempWay(10));
   Console.WriteLine(task2.Result);//读取Result属性自动造成当前线程阻塞,所以不用wait()
   System.Diagnostics.Trace.Assert(task2.IsCompleted);
}
class TempClass
{
    public static string TempWay(int data)
    {
        string tempstring = data.ToString();
        return tempstring;
    }
}

启动任务将从线程池获取一个新线程,创建第二个“控制点”,并在线程上执行委托(理解为任务是通过线程池来工作的)。
Task的背后的实现也是使用了线程池线程,但它的性能优于ThreadPool,因为它使用的不是线程池的全局队列,而是使用的本地队列,使线程之间的资源竞争减少。同时Task提供了丰富的API来管理线程。但是相对前面的两种耗内存,Task对于多核的CPU性能远超前两者,单核的CPU三者的性能没什么差别。
术语
为解决CPU核少线程多的矛盾,操作系统通过时间分片的机制来模拟多个线程并发运行。
Task某认使用线程池中的线程,他们都是后台线程。这意味着当主线程结束时,所有的任务也会随之停止。
调用Task的wait方法可以阻塞当前方法,直到任务完成,类似于线程对象的Join方法。
某认情况下,CLR会将任务运行在线程池上,这种线程非常适合执行短小的计算密集任务。如果要执行长时间的阻塞操作,则可以按照以下方式避免使用线程池中的线程。

 Task myTask = Task.Factory.StartNew(() =>。。。。,TaskCreationOptions.LongRunning)

在某个核心上更改执行线程的行动称为上下文切换。

同步上下文

它适用于所用富客户端用户界面的API

 using System.ComponentModel;
 SynchronizationContext _usingSync;
        public MainWindow()
        {
            InitializeComponent();
            _usingSync = SynchronizationContext.Current;
            new Thread(Work).Start();

        }
        void Work()
        {
            _usingSync.Post(_ => TextBox1.Text="111",null);
        }

Post的效果和BeginInvoke是相同的。

前台线程和后台线程

显式创建的线程是前台线程。只要前台线程中的任何一个正在运行,它就可以使应用程序保持活动状态,而后台线程则不会。一旦所有前台线程完成,应用程序结束,所有仍在运行的后台线程终止。

IsBackground = true

参考:
C#多线程和异步1——基本概念和使用方法
C#多线程和异步2–TaskHE async/await详解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程,任务,线程池的学习总结 的相关文章

  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat
  • 为什么 Assembly.GetManifestResourceStream() 中的文本以三个垃圾字符开头?

    我有一个 SQL 文件作为嵌入式资源添加到我的 VS NET 2008 项目中 每当我使用以下代码读取文件的内容时 返回的字符串总是以三个垃圾字符开头 然后是我期望的文本 我认为这与我正在使用的 Encoding Default 有关 但这
  • C# 按钮文本 Unicode 字符

    C 不想在按钮上放置 Unicode 字符 如果我将 u2129 放入按钮的 文本 属性中 按钮将显示 u2129 而不是 Unicode 字符 例如 我选择 2129 因为我可以在计算机上当前活动的字体中看到它 我之前看到过这个问题链接文
  • SQLite .NET 性能,如何加快速度?

    在我的系统上 约 86000 个 SQLite 插入需要长达 20 分钟 意味着每秒约 70 个插入 我要做数百万 我怎样才能加快速度 对每一行的 SQLiteConnection 对象调用 Open 和 Close 会降低性能吗 交易有帮
  • c# GDI边缘空白检测算法

    我正在寻找解决方案检测边缘空白c 位图 来自 c 托管 GDI 库 图像将是透明的 or white 大多数 400x 图片的尺寸为 8000x8000px 边缘周围有大约 2000px 的空白 找出边缘的最有效方法是什么 x y 高度和宽
  • 在编译时查找数组元素位置

    已编辑 大家好 我有一个元素数组 这些元素在程序的所有执行过程中都不会改变 并且其中的项目可以在自己的数组中包含子元素 我必须在处理数组之前准备好它 但是 因为我知道数组不会改变 所以我想将其声明为const 并在编译时准备所有这些 这样我
  • 为什么 GetThreadTimes 返回

    我试图测量线程中花费的时间以用于进度报告目的 但我从 GetThreadTimes 系统调用中得到非常奇怪的结果 给出以下程序 在 VS 2013 中编译 针对 NET 4 5 using System using System Diagn
  • 将 PDF 嵌入到 WPF 应用程序中

    我正在尝试在 WPF 应用程序中嵌入 显示 PDF 到目前为止 我已经尝试过这些解决方案 但没有成功 在 a 中显示 PDFWindowsFormsHost主持一个AxAcroPdf控制 类似于显示的内容here http hugeonio
  • C++ Socket选择和接收问题

    下面是我在套接字编程方面遇到问题的代码片段 在此之后select调用 如果我不在第 9 行放置睡眠 则在 Windows XP 上 第 11 行收到 1 个字节 而不是从服务器作为整数发送 4 个字节 当我检查 xmlSize 时 它 被设
  • 使用 LINQ 获取二维数组的最大列数

    无论如何 有没有使用 LINQ 来获取二维数组每列的最大值 假设我有以下内容 var arrays new double 5 100 我想获得最大的arrays 0 arrays 1 arrays 4 如何使用LINQ来做呢 我可以使用这样
  • 提供通用服务接口最具体实现的依赖注入机制

    我觉得我和标题一起玩了流行语宾果游戏 这是我所要求的一个简洁示例 假设我有一些实体的继承层次结构 class BaseEntity class ChildAEntity BaseEntity class GrandChildAEntity
  • 当操作系统显示语言为非英语时获取本地时区标识符

    奇怪的是 TimeZone CurrentTimeZone StandardName根据计算机显示语言返回本地化名称 我想要一个可以提供给的程序化标识符TimeZoneInfo在下面的代码中 TimeZoneInfo timeZoneInf
  • 为什么 SqlClient 在传递 SqlXml 时使用不必要的 XML 转换?

    我有一个关于从 C 代码将 xml 数据类型传递给查询的问题 首先 这是 SQL Server 上的一个表 CREATE TABLE dbo XmlTable id int IDENTITY 1 1 NOT NULL dat xml NOT
  • 如果启用优化,JIT 是否会始终内联此方法?

    我并不期望得到明确的 是 或 否 您可能拥有的任何知识我都会考虑作为答案 private String CalculateCharge Nullable

随机推荐