Task是.NET4.0加入的,跟線程池ThreadPool的功能相似,用Task開啓新任務時,會從線程池中調用線程,而Thread每次實例化都會建立一個新的線程。任務(Task)是架構在線程之上的,也就是說任務最終仍是要拋給線程(Thread)去執行。javascript
static void Main(string[] args) { for (int i = 0; i < 5; i++) { new Thread(Run1).Start(); } for (int i = 0; i < 5; i++) { Task.Run(() => { Run2(); }); } } static void Run1() { Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId); } static void Run2() { Console.WriteLine("Task調用的Thread Id =" + Thread.CurrentThread.ManagedThreadId); }
建立Task有兩種方式,一種是使用構造函數建立,另外一種是使用 Task.Factory.StartNew 進行建立。以下代碼所示java
1.使用構造函數建立Task多線程
Task t1 = new Task(MyMethod);架構
2.使用Task.Factory.StartNew 進行建立Taskide
Task t1 = Task.Factory.StartNew(MyMethod);函數
多任務測試
public void test() { Task[] tasks = new Task[10]; for (int i = 0; i < 100; i++) { if (i % 2 == 0) { tasks[i] = new Task(test2, (object)i);//傳參,必須是obj } else { tasks[i] = new Task(test1); } tasks[i].Start(); } Task.WaitAll(tasks);//等待全部線程執行完成後纔會繼續往下執行
//Task.WaitAll(tasks,5000);//最多等待5秒
Response.Write("執行完成"); } private void test1() { //do } private void test2(object ourl) { //do }
連續任務this
static void DownLoad(object str) { //下載文件 } static void ReadNews(Task obj) { //讀取文件 } static void Main(string[] args) { Task task = new Task(DownLoad, "人民日報"); Task task2 = task.ContinueWith(ReadNews); task.Start(); //DownLoad執行完才執行ReadNews }
Task返回值url
Task<string> t1 = Task.Factory.StartNew(() => "測試"); t1.Wait(); Console.WriteLine(t1.Result); Console.ReadLine(); //返回值能夠是任意的類型
Task線程池最大數量spa
這個TaskScheduler是微軟開源的一個任務調度器
LimitedConcurrencyLevelTaskScheduler.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Threading.Tasks; using System.Threading; /// <summary> ///LimitedConcurrencyLevelTaskScheduler 的摘要說明 /// </summary> public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler { // Indicates whether the current thread is processing work items. [ThreadStatic] private static bool _currentThreadIsProcessingItems; // The list of tasks to be executed private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks) // The maximum concurrency level allowed by this scheduler. private readonly int _maxDegreeOfParallelism; // Indicates whether the scheduler is currently processing work items. private int _delegatesQueuedOrRunning = 0; // Creates a new instance with the specified degree of parallelism. public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism) { if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism"); _maxDegreeOfParallelism = maxDegreeOfParallelism; } // Queues a task to the scheduler. protected sealed override void QueueTask(Task task) { // Add the task to the list of tasks to be processed. If there aren't enough // delegates currently queued or running to process tasks, schedule another. lock (_tasks) { _tasks.AddLast(task); if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism) { ++_delegatesQueuedOrRunning; NotifyThreadPoolOfPendingWork(); } } } // Inform the ThreadPool that there's work to be executed for this scheduler. private void NotifyThreadPoolOfPendingWork() { ThreadPool.UnsafeQueueUserWorkItem(_ => { // Note that the current thread is now processing work items. // This is necessary to enable inlining of tasks into this thread. _currentThreadIsProcessingItems = true; try { // Process all available items in the queue. while (true) { Task item; lock (_tasks) { // When there are no more items to be processed, // note that we're done processing, and get out. if (_tasks.Count == 0) { --_delegatesQueuedOrRunning; break; } // Get the next item from the queue item = _tasks.First.Value; _tasks.RemoveFirst(); } // Execute the task we pulled out of the queue base.TryExecuteTask(item); } } // We're done processing items on the current thread finally { _currentThreadIsProcessingItems = false; } }, null); } // Attempts to execute the specified task on the current thread. protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { // If this thread isn't already processing a task, we don't support inlining if (!_currentThreadIsProcessingItems) return false; // If the task was previously queued, remove it from the queue if (taskWasPreviouslyQueued) // Try to run the task. if (TryDequeue(task)) return base.TryExecuteTask(task); else return false; else return base.TryExecuteTask(task); } // Attempt to remove a previously scheduled task from the scheduler. protected sealed override bool TryDequeue(Task task) { lock (_tasks) return _tasks.Remove(task); } // Gets the maximum concurrency level supported by this scheduler. public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } } // Gets an enumerable of the tasks currently scheduled on this scheduler. protected sealed override IEnumerable<Task> GetScheduledTasks() { bool lockTaken = false; try { Monitor.TryEnter(_tasks, ref lockTaken); if (lockTaken) return _tasks; else throw new NotSupportedException(); } finally { if (lockTaken) Monitor.Exit(_tasks); } } }
使用方法
控制多線程數量,並實時輸出已完成任務數量
protected void Page_Load(object sender, EventArgs e) { Response.Write("<script type=\"text/javascript\">function load(i) {document.getElementById(\"now\").innerHTML = i;}</script>"); Response.Write("<span id='now'>0</span>/<span id='sum'>" + arr.Length + "</span>"); Response.Flush(); //設置最大線程數爲5 var scheduler = new LimitedConcurrencyLevelTaskScheduler(5); var Factory = new TaskFactory(scheduler); Task[] tasks = new Task[200]; int res = 0; for (int i = 0; i < 200; i++) { Task tk = Factory.StartNew(() => downFile((object)i)); tk.ContinueWith(t => { res++; Response.Write("<script>load(" + res.ToString() + ")</script>"); Response.Flush(); }); tasks[i] = tk; } Task.WaitAll(tasks); Response.Write("完成"); } private void downFile(object oid) { string iid= (string)id; //do... }
Task使用過程當中遇到的坑
使用過程當中發現有的task任務不執行,通過長時間調試發如今task調用的方法裏不少C#方法不可用,
例如HttpContext.Current.Request.Url、HttpContext.Current.Server.MapPath等方法不可用,真是坑
//end