网站首页 > 技术文章 正文
线程
被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。
异步委托
委托是方法的类型安全的引用。Delegate类 还支持异步的调用方法。在后台,delegate类 会创建一个执行任务的线程。
一个例子
static int TakeAWhile(int data,int ms)
{
Console.WriteLine("开始投票");
Thread.Sleep(ms);
Console.WriteLine("完成投票");
return ++data;
}
static void Main(string[] args)
{
TakeAWhileDelegate d1 = new TakeAWhileDelegate(TakeAWhile);
IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null);
while (!ar.IsCompleted)
{
Console.WriteLine(".");
Thread.Sleep(500);
}
int result = d1.EndInvoke(ar);
Console.WriteLine("result:{0}", result);
Console.ReadKey();
}
public delegate int TakeAWhileDelegate(int data, int ms);
回调
static void ArCallback(IAsyncResult ar)
{
TakeAWhileDelegate d1 = ar.AsyncState as TakeAWhileDelegate;
int result = d1.EndInvoke(ar);
Console.WriteLine("result:{0}", result);
}
static void Main(string[] args)
{
TakeAWhileDelegate d1 = new TakeAWhileDelegate(TakeAWhile);
IAsyncResult ar = d1.BeginInvoke(1, 3000,ArCallback,d1);
Console.ReadKey();
}
Lamdba委托
static void Main(string[] args)
{
TakeAWhileDelegate d1 = new TakeAWhileDelegate(TakeAWhile);
d1.BeginInvoke(1, 3000, ar =>
{
int result = d1.EndInvoke(ar);
Console.WriteLine("Result:{0}", result);
},null);
Console.ReadKey();
}
Thread类
using System.Threading;
Thread类的一类构造函数为接受ThreadStart和ParameterizedThreadStart类型的委托参数
ThreadStart委托定义了一个返回类型为void的无参数方法
创建Thread对象后,用Start()方法启动线程
一个例子
static void Main(string[] args)
{
var t1 = new Thread(ThreadMain);
t1.Start();
Console.WriteLine("这里是主线程!");
Console.ReadKey();
}
static void ThreadMain()
{
Console.Write("启动线程!");
}
给线程传递数据
static void Main(string[] args)
{
string Name = "张三";
var t1 = new Thread(ThreadMain);
t1.Start(Name);
Console.WriteLine("这里是主线程!");
Console.ReadKey();
}
static void ThreadMain(object o)
{
Console.WriteLine(o.ToString());
Console.Write("启动线程!");
}
Object可以是任意类型
后台线程
在用Thread类创建线程时,IsBackground默认是false。
static void ThreadMain()
{
Console.WriteLine("启动线程!");
Thread.Sleep(3000);
Console.WriteLine("完成线程!");
}
static void Main(string[] args)
{
var t1 = new Thread(ThreadMain)
{
Name = "NewThreadMain",
IsBackground = false
};
t1.Start();
Console.WriteLine("这里是主线程!");
}
因为新启的线程上加上了Sleep,这个有利于主线程结束
线程池
.NET Framework的ThreadPool类提供一个线程池,该线程池可用于执行任务、发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。那么什么是线程池?线程池其实就是一个存放线程对象的“池子(pool)”,他提供了一些基本方法,如:设置pool中最小/最大线程数量、把要执行的方法排入队列等等。ThreadPool是一个静态类,因此可以直接使用,不用创建对象。
微软官网说法如下:许多应用程序创建大量处于睡眠状态,等待事件发生的线程。还有许多线程可能会进入休眠状态,这些线程只是为了定期唤醒以轮询更改或更新的状态信息。 线程池,使您可以通过由系统管理的工作线程池来更有效地使用线程。
线程池
怎么使用线程池?其实线程池使用起来很简单,如下图
设置线程池最大最小:ThreadPool.SetMaxThreads (int workerThreads,int completionPortThreads)
设置可以同时处于活动状态的线程池的请求数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。还可以设置最小线程数。
将任务添加进线程池:ThreadPool.QueueUserWorkItem(new WaitCallback(方法名));
或ThreadPool.QueueUserWorkItem(new WaitCallback(方法名), 参数);
举个小例子,线程池中最多5个线程,执行一个方法60次,算5年总工资,如下:如果不采用线程池,恐怕要开60线程异步执行Run()方法,空间资源之浪费,可见一斑。
而现在我们最多用了5个线程,1秒内即可执行完毕,效率、性能都很好。
例子
static void Main(string[] args)
{
int ThreadCount = 0;
int CompletePortThreads = 0;
//参数1:workerThreads :线程池中辅助线程的最大数目。
//参数2:completionPortThreads :线程池中异步 I/ O 线程的最大数目。
ThreadPool.GetMaxThreads(out ThreadCount, out CompletePortThreads);
Console.WriteLine("ThreadCount:{0},CompletePortThreads:{1}"
, ThreadCount, CompletePortThreads);
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(JobAsThread);
}
Console.ReadKey();
}
static void JobAsThread(object state)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("loop {0},theadid {1}", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
}
}
大家看到的结果可能不一样
任务
.net4包含新名称空间 system.Threading.Tasks,它包含的类抽象出了线程功能。 在后台使用ThreadPool。 任务表示应完成的某个单元的工作。 这个单元的工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。 使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。
一个例子
static void Main(string[] args)
{
TaskFactory tf = new TaskFactory();
//这两个顺序是一定的
Task t1 = tf.StartNew(TaskMethod);
Task t2 = tf.StartNew(TaskMethod);
Console.WriteLine("Main");
Console.ReadKey();
}
static void TaskMethod()
{
Console.WriteLine("Running in a task");
Console.WriteLine("Task ID:{0}", Task.CurrentId);
}
带返回任务
static void Main(string[] args)
{
Task<int> task = CreateTask();
task.Start();
int result = task.Result;
Console.WriteLine(result);
Console.WriteLine("Main");
Console.ReadKey();
}
static Task<int> CreateTask()
{
return new Task<int>(() => ReturnMethod());
}
static int ReturnMethod()
{
return new Random().Next(1, 99);
}
Parallel类
Parallel类提供了数据和任务的并行性;
Parallel类是对线程的一个抽象。该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性。Paraller类定义了数据并行地For和ForEach的静态方法,以及任务并行的Invoke的静态方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,Paraller.Invoke()允许调用不同的方法。
Parallel.For
Parallel.For()方法类似C#语法的for循环语句,多次执行一个任务。但该方法并行运行迭代,迭代的顺序没有定义。 Parallel.For()方法中,前两个参数定义了循环的开头和结束,第三个参数是一个Action委托。Parallel.For方法返回类型是ParallelLoopResult结构,它提供了循环是否结束的信息。
一个例子
static void ForTest()
{
ParallelLoopResult plr =
Parallel.For(0, 10, i => {
Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
});
if (plr.IsCompleted)
Console.WriteLine("completed!");
}
Parallel.ForEach方法遍历实现了IEnumerable的集合,类似于foreach,但以异步方式遍历。没有确定遍历顺序。
static void ForeachTest()
{
string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
ParallelLoopResult plr = Parallel.ForEach<string>(data, s =>
{
Console.WriteLine(s);
});
if (plr.IsCompleted)
Console.WriteLine("completed!");
}
Timer 类
需要引入 System.Threading;
在很多时间我们都需要进行延迟执行,或是定时执行一些指定业务,这个时候使用 Timer 是最合适的,而且 Timer 是Cpu 级别处理对系统影响很少,就算创建上千上万个 Timer 也不会影响。
一个例子
//构建 Timer
//duetime:调用 callback 之前延迟的时间量(以毫秒为单位)。
//指定 Infinite 可防止启动计时器。 指定零 (0) 可立即启动计时器。
static Timer timer = new Timer(TimerCallBack,null, Timeout.Infinite,1000);
static void Main(string[] args)
{
//启动
timer.Change(0, 1000);
Console.ReadKey();
}
static void TimerCallBack(object state)
{
Console.WriteLine("Now:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
猜你喜欢
- 2024-10-25 优秀后端都应该具备哪些开发好习惯
- 2024-10-25 分享50个让你代码更好的小建议(好用的代码)
- 2024-10-25 Spring AOP里的静态代理和动态代理,你真的了解吗?
- 2024-10-25 代码保护软件 VMProtect 用户手册之准备项目: 使用标记
- 2024-10-25 写代码有这些想法,同事才不会认为你是复制粘贴程序员
- 2024-10-25 用Java创建对象的5种不同方法(java创建对象的几种方式)
- 2024-10-25 DispatcherObject(dispatchertimer)
- 2024-10-25 WPF效果第二百一十篇之NPOI插入图片
- 2024-10-25 【译】ConfigureAwait FAQ(configgenerator翻译)
- 2024-10-25 C# 实现 Linux 视频会议(源码,支持信创环境,银河麒麟,统信UOS)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)