微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Task.Factory.StartNew 测试

到底该用多少线程?线程数、cpu核心数、本地计算时间、等待时间的关系 线程数 = cpu核心数 * ( 本地计算时间 + 等待时间 ) / 本地计算时间

下面是Task.Factory.StartNew和自己写的TaskHelper.LargeTask.Run对比测试

 

一、Task.Factory.StartNew 使用 TaskCreationoptions.LongRunning 参数

代码

private int n = 50000; //问题规模
int t = 25; 等待时间
int pageSize = 1000; 打印分页

void TestTaskStartNew()
{
    Task.Factory.StartNew(() =>
    {
        Stopwatch stopwatch = Stopwatch.StartNew();

        List<Task> taskList = new List<Task>();
        for (int i = 0; i <= n; i++)
        {
            Task task = Task.Factory.StartNew((obj) =>
            {
                Thread.Sleep(t); 等待时间

                int index = (int)obj;
                if (index % pageSize == 0)
                {
                    this.TryInvoke2(() =>
                    {
                        textBox1.AppendText(index.ToString() + "  ");
                    });
                }
            },i,TaskCreationoptions.LongRunning);
            taskList.Add(task);
        }
        Task.WaitAll(taskList.ToArray());

        
        {
            textBox1.AppendText(string.Format("\r\n【Task.Factory.StartNew 问题规模:{0} 等待时间:{1} 耗时:{2}秒】\r\n,n,t,stopwatch.Elapsed.TotalSeconds));
        });
    });
}

 TestTaskHelper()
{
    Task.Factory.StartNew(() =>)
        {
            Task task = TaskHelper.LargeTask.Run((obj) =>\r\n【TaskHelper.LargeTask.Run {3}线程 问题规模:{0} 等待时间:{1} 耗时:{2}秒】\r\nView Code

测试结果:

0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 11000 12000 13000 14000 15000 16000 17000 18000 19000 20000 21000 22000 23000 24000 25000 26000 27000 28000 29000 30000 31000 32000 33000 34000 35000 36000 37000 38000 39000 40000 41000 42000 43000 44000 45000 46000 47000 48000 49000 50000
【TaskHelper.LargeTask.Run 128线程 问题规模:50000 等待时间:25 耗时:10.5975181秒】
0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 11000 12000 13000 14000 15000 16000 17000 18000 19000 20000 21000 22000 23000 24000 25000 26000 27000 28000 29000 30000 31000 32000 33000 34000 35000 36000 37000 38000 39000 40000 41000 42000 43000 44000 45000 46000 47000 48000 49000 50000
【Task.Factory.StartNew 问题规模:50000 等待时间:25 耗时:8.2380754秒】
0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 11000 12000 13000 14000 15000 16000 17000 18000 19000 20000 21000 22000 23000 24000 25000 26000 27000 28000 29000 30000 31000 32000 33000 34000 35000 36000 37000 38000 39000 40000 41000 42000 43000 44000 45000 46000 47000 48000 49000 50000
【TaskHelper.LargeTask.Run 128线程 问题规模:50000 等待时间:25 耗时:10.4376939秒】
0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 11000 12000 13000 14000 15000 16000 17000 18000 19000 20000 21000 22000 23000 24000 25000 26000 27000 28000 29000 30000 31000 32000 33000 34000 35000 36000 37000 38000 39000 40000 41000 42000 43000 44000 45000 46000 47000 48000 49000 50000
【Task.Factory.StartNew 问题规模:50000 等待时间:25 耗时:9.2322552秒】

测试结果说明:

我的电脑的cpu是i5-8265U,4核8线程
根据等待时间设置合适的线程数对TaskHelper.LargeTask.Run有利
使用TaskHelper.LargeTask.Run运行时的cpu占用在5%以下,创建128个线程的瞬间cpu占用达到30%,使用Task.Factory.StartNew运行时的cpu占用接近100%
资源释放情况:Task.Factory.StartNew使用TaskCreationoptions.LongRunning参数运行完成后线程数立即释放,句柄数未立即释放,而TaskHelper.LargeTask.Run提供了手动释放的方法可以立即释放线程数和句柄数,但需要手动调用才能释放

 

 二、Task.Factory.StartNew 不使用 TaskCreationoptions.LongRunning 参数

代码

2000; 100; View Code

测试结果:

0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000
【TaskHelper.LargeTask.Run 96线程 问题规模:2000 等待时间:100 耗时:2.1529565秒】
0 2000 100 200 300 400 500 600 700 800 900 1900 1000 1100 1200 1300 1400 1500 1600 1700 1800
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:17.309869秒】
0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000
【TaskHelper.LargeTask.Run 96线程 问题规模:2000 等待时间:100 耗时:2.143763秒】
0 2000 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:8.8674353秒】
0 2000 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:6.5490833秒】
0 2000 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:5.1381533秒】
0 2000 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:4.434294秒】
0 2000 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:4.329009秒】
2000 0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:3.6231239秒】
2000 0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900
【Task.Factory.StartNew 问题规模:2000 等待时间:100 耗时:3.6303149秒】

测试结论:

Task.Factory.StartNew在不使用TaskCreationoptions.LongRunning参数时,运行大量耗时任务,线程数增加缓慢,导致需要花费很长时间,如果线程池耗尽,或者线程池未耗尽但有大量耗时任务时,其它任务调用Task.Factory.StartNew会有延迟

我想了一天,多任务还是不要共用线程池比较好,一个任务一个线程池,互不干扰,TaskHelper.LargeTask.Run就是按这个思路写的,不知道可有问题

 

附:

LimitedTaskScheduler代码

@H_502_253@

using System;
 System.Collections.Concurrent;
 System.Collections.Generic;
 System.Linq;
 System.Runtime.InteropServices;
 System.Text;
 System.Threading;
 System.Threading.Tasks;

namespace Utils
{
    public class LimitedTaskScheduler : TaskScheduler,Idisposable
    {
        #region 外部方法
        [DllImport(kernel32.dll",EntryPoint = SetProcessWorkingSetSize)]
        static extern int SetProcessWorkingSetSize(IntPtr process,int minSize,1)"> maxSize);
        #endregion

        #region 变量属性事件
        private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
        List<Thread> _threadList = new List<Thread>int _threadCount = ;
        int _timeOut = Timeout.Infinite;
        private Task _tempTask;

         ThreadCount
        {
            get
            {
                return _threadCount;
            }
        }
        #region 构造函数
        public LimitedTaskScheduler(int threadCount = 10)
        {
            CreateThreads(threadCount);
        }
        #region override GetScheduledTasks
        protected override IEnumerable<Task> GetScheduledTasks()
        {
             _tasks;
        }
        #region override TryExecuteTaskInline
        override bool TryExecuteTaskInline(Task task,1)">bool taskwasprevIoUslyQueued)
        {
            return false;
        }
        #region override QueueTask
         QueueTask(Task task)
        {
            _tasks.Add(task);
        }
        #region 资源释放
        /// <summary>
        /// 资源释放
         如果尚有任务在执行,则会在调用方法的线程上引发System.Threading.ThreadAbortException,请使用Task.WaitAll等待任务执行完毕后,再调用方法
        </summary>
         dispose()
        {
            _timeOut = 100;

            foreach (Thread item in _threadList)
            {
                item.Abort();
            }
            _threadList.Clear();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.Osversion.Platform == PlatformID.Win32NT)
            {
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle,-1,-1);
            }
        }
        #region 创建线程池
         创建线程池
        void CreateThreads(int? threadCount = null)
        {
            if (threadCount != null) _threadCount = threadCount.Value;
            _timeOut = Timeout.Infinite;

            0; i < _threadCount; i++)
            {
                Thread thread = new Thread(new ThreadStart(() =>
                {
                    Task task;
                    while (_tasks.TryTake(out task,_timeOut))
                    {
                        TryExecuteTask(task);
                    }
                }));
                thread.IsBackground = true;
                thread.Start();
                _threadList.Add(thread);
            }
        }
        #region 全部取消
         全部取消
         CancelAll()
        {
             _tempTask)) { }
        }
        #endregion

    }
}
View Code

TaskHelper代码

 Utils
{
    <summary>
     Task帮助类基类
    </summary>
     TaskHelper
    {
        #region UI任务
        static LimitedTaskScheduler _UITask;
         UI任务(4个线程)
         LimitedTaskScheduler UITask
        {
            if (_UITask == null) _UITask = new LimitedTaskScheduler(4);
                 _UITask;
            }
        }
        #region 计算任务
         LimitedTaskScheduler _CalcTask;
         计算任务(8个线程)
         LimitedTaskScheduler CalcTask
        {
            if (_CalcTask == null) _CalcTask = 8 _CalcTask;
            }
        }
        #region 网络请求
         LimitedTaskScheduler _RequestTask;
         网络请求(32个线程)
         LimitedTaskScheduler RequestTask
        {
            if (_RequestTask == null) _RequestTask = 32 _RequestTask;
            }
        }
        #region 数据库任务
         LimitedTaskScheduler _DBTask;
         数据库任务(32个线程)
         LimitedTaskScheduler DBTask
        {
            if (_DBTask == null) _DBTask =  _DBTask;
            }
        }
        #region IO任务
         LimitedTaskScheduler _IOTask;
         IO任务(8个线程)
         LimitedTaskScheduler IOTask
        {
            if (_IOTask == null) _IOTask =  _IOTask;
            }
        }
        #region 大线程池任务
         LimitedTaskScheduler _LargeTask;
         大线程池任务(64个线程)
         LimitedTaskScheduler LargeTask
        {
            if (_LargeTask == null) _LargeTask = 128 _LargeTask;
            }
        }
        

    }
}
View Code

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐