多线程知识总结

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

多线程知识总结

未闻·Yokeqi   2019-11-18 我要评论

多线程永远都是一个热门的话题,因为直接关系到程序的性能提升,也是开发必须要懂得的知识点,其实在网上随便一搜都会有海量的文章说这个话题,所以这里对于基础知识废话不多说,只结合多年实践做一个总结。

==========  原创作品    作者:Yokeqi    出处:博客园  ==========

一、知识点概括

二、具体实例演示如何实现

> Thread

//ThreadPool.GetMaxThreads(out int maxTCount, out int maxPCount);
//ThreadPool.GetMinThreads(out int minTCount, out int minPCount);
//ThreadPool.SetMaxThreads(maxTCount, maxPCount);// 调整最大线程数
//ThreadPool.SetMinThreads(minTCount, minPCount);// 调整最小线程数

long tick = C_ITEM_COUNT;
ManualResetEvent signal = new ManualResetEvent(false);
Console.WriteLine("========== 示例:采用Thread执行处理 ==========");
for (int i = 0; i < C_ITEM_COUNT; i++)
{
    new Thread((obj) =>
    {
        Thread.Sleep(500);
        Console.Write(" {0} ", obj);
        if (Interlocked.Decrement(ref tick) == 0)
            signal.Set();
    }).Start(i);
}
Console.Write(" 等待子线程执行 ");
signal.WaitOne();
Console.WriteLine();
Console.WriteLine("全部线程执行完毕,按任意键继续...");

> ThreadPool

tick = C_ITEM_COUNT;
signal.Reset();
Console.WriteLine();
Console.WriteLine("========== 示例:采用ThreadPool执行处理 ==========");
for (int i = 0; i < C_ITEM_COUNT; i++)
{
    ThreadPool.QueueUserWorkItem((obj) =>
    {
        Thread.Sleep(500);
        Console.Write(" {0} ", obj);
        if (Interlocked.Decrement(ref tick) == 0)
            signal.Set();
    }, i);
}
Console.Write(" 等待子线程执行 ");
signal.WaitOne();
Console.WriteLine();
Console.WriteLine("全部线程执行完毕,按任意键继续...");

> Task

tick = C_ITEM_COUNT;
signal.Reset();
Console.WriteLine();
Console.WriteLine("========== 示例:采用Task执行处理,注意取消了处理{0}的进程 ==========", C_ITEM_COUNT - 2);
var tasks = new Tuple<Task, CancellationTokenSource>[C_ITEM_COUNT];
for (int i = 0; i < C_ITEM_COUNT; i++)
{
    var cts = new CancellationTokenSource();
    var task = Task.Factory.StartNew((obj) =>
    {
        Thread.Sleep(500);
        Console.Write(" {0} ", obj);
    }, i, cts.Token);
    task.ContinueWith((t) =>
    {
        if (Interlocked.Decrement(ref tick) == 0)
            signal.Set();
    });
    tasks[i] = new Tuple<Task, CancellationTokenSource>(task, cts);
}

tasks[C_ITEM_COUNT - 2].Item2.Cancel();// 取消线程。

Console.Write(" 等待子线程执行 ");
signal.WaitOne();
Console.WriteLine();
Console.WriteLine("全部线程执行完毕,按任意键继续...");

> Parallel

tick = C_ITEM_COUNT;
signal.Reset();
Console.WriteLine();
Console.WriteLine("========== 示例:采用Parallel执行处理 ==========");
Parallel.For(0, C_ITEM_COUNT, obj =>
{
    Thread.Sleep(500);
    Console.Write(" {0} ", obj);
    if (Interlocked.Decrement(ref tick) == 0)
        signal.Set();
});

Console.Write(" 等待子线程执行 ");
signal.WaitOne();
Console.WriteLine();
Console.WriteLine("全部线程执行完毕,按任意键继续...");

执行结果如下

三、性能对比

> 循环数:200,线程池参数:默认

> 循环数:200,线程池参数:50 - 1000

> 循环数200,线程池参数:100-1000

 

> 循环数200,线程池参数:200-1000

 

最大线程数 ~ 最小线程数 Thread(ms) ThreadPool(ms) Task(ms) Parallel(ms)
2047/1000 ~ 12/12 2712.09 8057.14 8585.01 7526.57
1000/1000 ~ 50/50 2733.25 2289.96 2218.29 3660.33
1000/1000 ~ 100/100 2503.08 1620.73 1534.50 1742.78
1000/1000 ~ 200/200 2999.27 1436.24 1150.21 935.22

 四、结论

> Thread就像脱缰的野马,不受控制,创建多少就运行多少,可能少量时效率是高了,量大的时候除了性能没优势,还可能导致句柄泄露。

> ThreadPool与Task类似,但Task相比效率更高用法更灵活。

> Parallel自带了同步功能,不需要用信号量来做额外的同步等待。

> ThreadPool、Task、Parallel的性能都取决于线程池最大线程数和最小线程数。

> 推荐使用 Task 和 Parallel,具体用哪个可以参考用法自己斟酌。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们