Asp.Net任務Task和線程Thread

Task是.NET4.0加入的,跟線程池ThreadPool的功能相似,用Task開啓新任務時,會從線程池中調用線程,而Thread每次實例化都會建立一個新的線程。任務(Task)是架構在線程之上的,也就是說任務最終仍是要拋給線程(Thread)去執行。javascript

一、首次構造一個Task對象時,他的狀態是Created。
二、當任務啓動時,他的狀態變成WaitingToRun。
三、Task在一個線程上運行時,他的狀態變成Running。
四、任務中止運行,等待他的任何子任務時,狀態變成WaitingForChildrenToComplete。
五、任務徹底結束時,它進入如下三個狀態之一:RanToCompletion,Canceled或者Faulted。
六、一個Task<TResult>運行完成時,可經過Task<TResult>的Result屬性來查詢任務的結果,
七、一個Task或者Task<TResult>出錯時,能夠查詢Task的Exception屬性來得到任務拋出的未處理的異常,該屬性老是返回一個AggregateException對象,他包含全部未處理的異常。
八、爲簡化代碼,Task提供了幾個只讀的Boolean屬性,IsCanceled,IsFaulted,IsCompleted。
九、注意,當Task處於RanToCompleted,Canceled或者Faulted狀態時,IsCompleted返回True。
十、爲了判斷一個Task是否成功完成,最簡單的方法是:if(task.Status == TaskStatus.RanToCompletion)。
十一、task的ContinueWith方法用於在一個任務完成後發起一個新任務。

任務Task和線程Thread的區別:

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有兩種方式,一種是使用構造函數建立,另外一種是使用 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);
        }
    }
}
View Code

使用方法

控制多線程數量,並實時輸出已完成任務數量

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

相關文章
相關標籤/搜索