全面解析C# Task

Task作为C#异步的核心,类中的每个方法有必要学习一番,而部分重点方法更要尝试分析一下源码。

首先,Task位于System.Threading.Tasks命名空间下。

官方对其定义:Represents an asynchronous operation.

先看一下Task的类注释,这里讲了很多重点。

第一条注释:

Task instances may be created in a variety of ways. The most common approach is by using the Task type's Factory property to retrieve a System.Threading.Tasks.TaskFactory instance that can be used to create tasks for several purposes.

也就是说,我们可以使用Task.Factory.StartNew这个方法的很多重载方式去创建一个适合应用场景的Task,下面是应用实例:

static void Main(string[] args)
{
     Console.WriteLine("Main1 Thread" + Thread.CurrentThread.ManagedThreadId);
     Task.Factory.StartNew(() => 
     {
         Console.WriteLine("Main2 Thread" + Thread.CurrentThread.ManagedThreadId);
     });
     Console.ReadLine();
}

//结果:
Main1 Thread1
Main2 Thread3

第二条注释:

The Task class also provides constructors that initialize the Task but that do not schedule it for execution. For performance reasons, TaskFactory's StartNew method should be the preferred mechanism for creating and scheduling computational tasks, but for scenarios where creation and scheduling must be separated, the constructors may be used, and the task's Start() method may then be used to schedule the task for execution at a later time.

意思就是

如果你想建立一个Task并且立即执行它,使用Task.Factory.StartNew(),这样做性能更好

如果你想建立一个Task,想在合适的时候执行它,那么使用Task构造器做初始化:

static void Main(string[] args)
{
    //初始化这个task,但不执行
    Task task = new Task(() => 
    {
       //doSomething
    });
    //做第一件事
    //做第二件事
    //做第N件事
    //之后再执行这个task
    task.Start();
    Task.Factory.StartNew(() => { });
}

这样更加灵活。

第三条注释:

All members of Task, except for Dispose(),are thread-safe and may be used from multiple threads concurrently.

除了Dispose()方法,Task的其他所有成员都是线程安全的!

第四条注释:

For operations that return values, the System.Threading.Tasks.Task{TResult} class should be used.

如果你想使用有返回值的Task,可以使用Task<Tresult>:

Task<string> task = new Task<string>(() =>
{
    //doSomething
    return "可以返回泛型类型的值";
});
Console.WriteLine("task的返回值是:" + task.Result);

输出:
可以返回泛型类型的值

最后一条注释,表述了一些成员变量的作用:

For developers implementing custom debuggers, several internal and private members of Task may be useful (these may change from release to release).
①The Int32 m_taskId field serves as the backing store for the Id property, however accessing this field directly from a debugger may be more efficient than accessing the same value through the property's getter method (the s_taskIdCounter Int32 counter is used to retrieve the next available ID for a Task). 
②the Int32 m_stateFlags field stores information about the current lifecycle stage of the Task,information also accessible through the Status property. 
③The m_action System.Object field stores a reference to the Task's delegate, and the m_stateObject System.Object field stores the async state passed to the Task by the developer. Finally, for debuggers that parse stack frames, the InternalWait method serves a potential marker for when a Task is entering a wait operation.

①直接使用m_taskId比使用ID的getter方法更好,因为其实可以从源码看到:

public int Id 
{ 
    get 
    { 
        if (m_taskId == 0) 
        { 
            int newId = NewId(); 
            Interlocked.CompareExchange(ref m_taskId, newId, 0); 
        } 
        return m_taskId; 
    } 
}

Id的值是从m_taskId中取的。

②m_stateFlags和Status都记录了当前Task的生命周期阶段,而Status的值是从m_stateFlags中取的:

public TaskStatus Status
{
    get
    {
        TaskStatus rval;

        int sf = m_stateFlags;
 
        if ((sf & TASK_STATE_FAULTED) != 0) rval = TaskStatus.Faulted;
        else if ((sf & TASK_STATE_CANCELED) != 0) rval = TaskStatus.Canceled;
        else if ((sf & TASK_STATE_RAN_TO_COMPLETION) != 0) rval = TaskStatus.RanToCompletion;
        else if ((sf & TASK_STATE_WAITING_ON_CHILDREN) != 0) rval = TaskStatus.WaitingForChildrenToComplete;
        else if ((sf & TASK_STATE_DELEGATE_INVOKED) != 0) rval = TaskStatus.Running;
        else if ((sf & TASK_STATE_STARTED) != 0) rval = TaskStatus.WaitingToRun;
        else if ((sf & TASK_STATE_WAITINGFORACTIVATION) != 0) rval = TaskStatus.WaitingForActivation;
        else rval = TaskStatus.Created;
 
        return rval;
     }
 }

③m_action存储Task的委托的引用,m_stateObject存储异步状态。然而当我想用vs开始一些测试时,发现根本调用不了这些成员,这里我就想到了我之前从《CLR via C#》当中看到的这么一段话:

高级语言(包括C#)通常只公开了CLR全部功能的一个子集。然而IL汇编语言允许开发人员访问CLR的全部功能。

所以,如果我想探寻这些变量的秘密,或许我嘚从IL入手。

④InternalWait()方法会在Wait()方法中被调用,作为判断task是否完成的一个标记。

public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
{
	//......
    // Wait, and then return if we're still not done.
    if (!InternalWait(millisecondsTimeout, cancellationToken))
        return false;
    //......
}

说完了Task的重点注释之后,我们来看一下Task实现了哪些接口:

IAsyncResult:

encapsulate the results of an async operation 封装异步的操作结果

成员:

//获取一个bool值判断异步操作是否完成

bool IsCompleted 

//获取一个WaitHandle,该对象主要是有一些等待异步操作完成的动作

WaitHandle AsyncWaitHandle

Object AsyncState

bool CompeltedSynchronously
发布了3 篇原创文章 · 获赞 3 · 访问量 88

猜你喜欢

转载自blog.csdn.net/qq_38312617/article/details/104380964