当前位置: 首页 > news >正文

.NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调

windows系统是一个多线程的操作系统。一个程序至少有一个进程,一个进程至少有一个线程。进程是线程的容器,一个C#客户端程序开始于一个单独的线程,CLR(公共语言运行库)为该进程创建了一个线程,该线程称为主线程。例如当我们创建一个C#控制台程序,程序的入口是Main()函数,Main()函数是始于一个主线程的。它的功能主要 是产生新的线程
和执行程序。C#是一门支持多线程的编程语言,通过Thread类创建子线程,
引入using System.Threading命名空间。
多线程优点:
1、 多线程可以提高CPU的利用率,因为当一个线程处于等待状态的时候,CPU会去执行另外的线程
2、 提高了CPU的利用率,就可以直接提高程序的整体执行速度
多线程缺点:
1、线程开的越多,内存占用越大
2、协调和管理代码的难度加大,需要CPU时间跟踪线程
3、线程之间对资源的共享可能会产生可不遇知的问题
C#中的线程分为前台线程和后台线程,线程创建时不做设置默认是前台线程。即线程属性IsBackground=false。
Thread.IsBackground = false;//false:设置为前台线程,系统默认为前台线程。
进程》》线程,进程是线程的容器。
程序只能有一个进程,但可以有多个线程,

Join方法主要是用来阻塞调用线程,直到某个线程终止或经过了指定时间为止。官方的解释比较乏味,通俗的说就是创建
一个子线程,给它加了这个方法,其它线程就会暂停执行,直到这个线程执行完为止才去执行(包括主线程)。
public void Join();
public bool Join(int millisecondsTimeout); //毫秒数
public bool Join(TimeSpan timeout); //时间段
线程的Priority

优先级越高表示CPU分配给该线程的时间片越多,执行时间就多
优先级越低表示CPU分配给该线程的时间片越少,执行时间就少

线程安全:
线程安全是指在当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取
完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

private Object thisLock = new Object();//创建对象锁
lock (thisLock)
{

     // Critical code section

}

线程池
上面介绍了介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程往往是大量的和更为复杂的,这时,
每次都创建线程、启动线程。从性能上来讲,这样做并不理想(因为每使用一个线程就要创建一个,需要占用系统开销);
从操作上来讲,每次都要启动,比较麻烦。为此引入的线程池的概念
系统在创建线程是很复杂的过程,而且很浪费资源的。

1.减少在创建和销毁线程上所花的时间以及系统资源的开销
2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”

在什么情况下使用线程池?
1.单个任务处理的时间比较短
2.需要处理的任务的数量大
线程池最多管理线程数量=“处理器数 * 250”。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000
通过线程池创建的线程默认为后台线程,优先级默认为Normal。

首先说下,invoke和begininvoke的使用有两种情况:

  1. control中的invoke、begininvoke。
  2. delegrate中的invoke、begininvoke。
    这两种情况是不同的,我们这里要讲的是第1种。下面我们在来说下.NET中对invoke和begininvoke的官方定义。
    control.invoke(参数delegate)方法:在拥有此控件的基础窗口句柄的线程上执行指定的委托。
    control.begininvoke(参数delegate)方法:在创建控件的基础句柄所在线程上异步执行指定委托。

    根据这两个概念我们大致理解invoke表是同步、begininvoke表示异步。

在 WinForm开发过程中经常会用到线程,有时候还往往需要在线程中访问线程外的控件,比如:设置textbox的Text属性等
等。如果直接设置程序必 定会报出:从不是创建控件的线程访问它,这个异常。通常我们可以采用两种方法来解决。一是通
过设置control的属性。二是通过delegate,而通 过delegate也有两种方式,一种是常用的方式,另一种就是匿名方式。下面
分别加以说明.
首先,通过设置control的一个属性值为false.我们可以在Form_Load方法中添加:
**Control.CheckForIllegalCrossThreadCalls=false;**来解决。设置为false表示不对错误线程的调用进行捕获。
这样在线程中对textbox的Text属性进行设置时就不会再报错了。
其次,通过delegate的方法来解决。
delegate void SafeSetText(string strMsg);
private void SetText(string strMsg)
{
if(textbox1.InvokeRequired)
{
SafeSetText objSet=new SafeSetText(SetText);
textbox1.Invoke(objSet,new object[]{strMsg});
}
else
{
textbox1.Text=strMsg;
}
}
在线程内需要设置textbox的值时调用SetText方法既可。我们还可以采用另一种委托的方式来实现,那就是匿名代理,例
如:
delegate void SafeSetText(string strMsg);
private void SetText2(string strMsg)
{
SafeSetText objSet = delegate(string str)
{
textBox1.Text = str;
}
textBox1.Invoke(objSet,new object[]{strMsg});
}
以上可以用lambda => 语法 更加简洁 【=> 读goes】 跟JavaScript中箭头函数类似。

nvoke方法的参数很简单,一个委托,一个参数表(可选),而Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,如果是,直接执行委托指向的方法,
如果不是,它将切换到UI线程,然后执行委托指向的方法。不管当前线程是不是UI线程,Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的线程(如果需要的话),返回。
所以Invoke方法的参数和返回值和调用他的委托应该是一致的。

IAsyncResult result = handler.BeginInvoke(1,2,null,null);
BeginInvoke : 开始一个异步的请求,调用线程池中一个线程来执行,
返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,他存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
注意: BeginInvoke和EndInvoke必须成对调用.即使不需要返回值,但EndInvoke还是必须调用,否则可能会造成内存泄漏
IAsyncResult.AsyncState 属性:
获取用户定义的对象,它限定或包含关于异步操作的信息。 例如:
static void AddComplete(IAsyncResult result)
{
AddHandler handler = (AddHandler)result.AsyncState;
Console.WriteLine(handler.EndInvoke(result));
。。。。。
}

异步回调当主线程在执行一段代码的时候,我们用委托执行了一个线程,这个线程要返回一个结果,关键是什么时候返回这个结果,异步回调就是在这个线程执行完成后立即返回这个线程的结果,然后继续执行主线程的方法。异步回调在JavaScript中应用特别常见,而且特别灵活,特别方便,比.NET 方便多了。
**异步执行:**在主线程在执行的时候,打开一个子线程,主线程继续执行,当主线程需要子线程运行的结果的时候,主线程直接调用子线程运行结果,如果在调用的时候子线程还没有执行完成,主线程等待,直到子线程执行完成,主线程再继续执行。
这边面就涉及到异步回调了,在使用异步结果的地方,必须在IAsyncResult 对应的处理。
使用异步结果必须在异步回调中写。

static void Main(string[] args)
{
#region 异步执行 Func 泛型最后一个参数类型就是返回的类型。
Func<int, int, int> d2 = TakeAWhile;
// 1,3000是委托对应方法的参数,后面参数AsyncCallBack委托,第二个参数Object asyncState,同时都可以为null的。
IAsyncResult ar = d2.BeginInvoke(1, 3000, null, null);
while (!ar.IsCompleted)
{
Console.Write(“.”);
Thread.Sleep(50);
}
//EndInvoke:一个参数列表、另外一个参数IAsyncResult:表示异步操作的状态。
int result = d2.EndInvoke(ar);
Console.Write(“result:{0}”,result);
#endregion
}
static int TakeAWhile(int data, int ms)
{
Console.Write(“TakesAWhile started”);
Thread.Sleep(ms);
Console.WriteLine(“TakeAWhile Completed”);
return ++data;
}

异步回调

static void Main(string[] args)
{
#region 异步回调
Func<int, int, int> dl = TakeAWhile;
dl.BeginInvoke(1, 3000, TakesAWhileCompleted, dl);
for (int i = 0; i < 100; i++)
{
Console.Write(“.”);
Thread.Sleep(50);
}
#endregion
}
static int TakeAWhile(int data, int ms)
{
Console.Write(“TakesAWhile started”);
Thread.Sleep(ms);
Console.WriteLine(“TakeAWhile Completed”);
return ++data;
}
// ar 是dl委托异步操作的结果。
static void TakesAWhileCompleted(IAsyncResult ar)
{
if (ar == null)
throw new ArgumentNullException(“ar”);
Func<int, int, int> dl = (Func<int, int, int>)ar.AsyncState;
int result = dl.EndInvoke(ar);
Console.WriteLine(“Result:{0}”,result);
}


        static void Main(string[] args)

        {

            Console.WriteLine("Main ThreadId = " + Thread.CurrentThread.ManagedThreadId);
            //给委托赋值
            Func<long, long> delegateMethod = new Func<long, long>(CalcSum);
            //异步执行委托,这里把委托本身作为asyncState对象传进去,在回调函数中需要使用委托的EndInvoke来获得结果

            delegateMethod.BeginInvoke(200, DoneCallback, delegateMethod);
            //Console.WriteLine("444"+delegateMethod.EndInvoke(delegateMethod.BeginInvoke(200, DoneCallback, "5fr")));
            异步执行委托,抛出异常
            //delegateMethod.BeginInvoke(10000000000, DoneCallback, delegateMethod);
            Console.ReadLine();
        }

        //委托回调函数
        static void DoneCallback(IAsyncResult asyncResult)
        {

            //到这儿委托已经在异步线程中执行完毕

            Console.WriteLine("DoneCallback ThreadId = " + Thread.CurrentThread.ManagedThreadId);
            Func<long, long> method = (Func<long, long>)asyncResult.AsyncState;
            //委托执行的异常会在EndInvoke时抛出来
            try
            {
                //使用BeginInvoke时传入委托的EndInvoke获得计算结果,这时候计算结果已经出来了,有异常的话也在这儿抛出来
                long sum = method.EndInvoke(asyncResult);
                Console.WriteLine("sum = {0}", sum);
            }
            catch (OverflowException)
            {
                Console.WriteLine("运算溢出了");
            }
        }
        //委托方法
        static long CalcSum(long topLimit)
        {
            //委托在另一个线程中开始执行
            Console.WriteLine("Calc ThreadId = " + Thread.CurrentThread.ManagedThreadId);
            checked
            {
                long result = 0;
                for (long i = 0; i < topLimit; i++)
                {
                    result += i;
                }
                return result;
            }
        }

相关文章:

  • C++程序调试详解(包括打断点 单步调试 数据断点...)
  • 数据结构之图
  • Opencv项目实战:03 扫描二维码条形码
  • 智能优化算法:沙猫群算法—附代码
  • node---express
  • [Linux]进程间通信(进程间通信介绍 | 匿名管道 | 命名管道)
  • Allegro Design Entry HDL(OrCAD Capture HDL)RF-PCB菜单详细介绍
  • 电商数仓项目中各层的表
  • 移动安全规范 — 3 -个人密码(PIN)传输规范
  • Spring之AOP思想
  • TypeScript 小结
  • Netty(10)协议设计与解析(IdleStateHandler:空闲检测器、心跳)
  • PostgreSQL数据库统计信息——analyze大致流程
  • C开发环境与基础
  • Android系统_MSM8953_android10_adb连接adbd加入密码检测
  • 2017-08-04 前端日报
  • 2017年终总结、随想
  • ES学习笔记(12)--Symbol
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • leetcode98. Validate Binary Search Tree
  • passportjs 源码分析
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Selenium实战教程系列(二)---元素定位
  • SSH 免密登录
  • 二维平面内的碰撞检测【一】
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 删除表内多余的重复数据
  • 以太坊客户端Geth命令参数详解
  • 昨天1024程序员节,我故意写了个死循环~
  • !!Dom4j 学习笔记
  • # 安徽锐锋科技IDMS系统简介
  • #### go map 底层结构 ####
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • $L^p$ 调和函数恒为零
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转) ns2/nam与nam实现相关的文件
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)Linux整合apache和tomcat构建Web服务器
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET Framework 服务实现监控可观测性最佳实践
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .net mvc 获取url中controller和action
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .Net程序帮助文档制作
  • .Net面试题4
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...
  • :=
  • @vue/cli 3.x+引入jQuery
  • [2021]Zookeeper getAcl命令未授权访问漏洞概述与解决
  • [Android开源]EasySharedPreferences:优雅的进行SharedPreferences数据存储操作
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)