必威体育Betway必威体育官网
当前位置:首页 > IT技术

C# 异步编程TaskScheduler

时间:2019-09-12 04:11:06来源:IT技术作者:seo实验室小编阅读:87次「手机版」
 

taskscheduler

C# 异步编程TaskScheduler

1.Task

Task任务,其本身不会执行任何代码,需要使用线程来执行Task的代码,默认情况下Task的运行在线程池中的线程中。Task类并没有提供Thread. Abort这样强制结束的函数,因为Task代码不是由自己本身执行,而是由线程Thread执行。如果Task已经在线程Thread中执行,调用了Task. Abort这样的函数强制结束,此时执行它的线程将不知道下一步要执行的代码,所以Task没有Abort这样的成员函数。Task本身不应该去杀死执行它线程,线程不属于某一个Task,对于Task来说线程是公共资源,如果杀死线程只会违背Task的初衷,Task本身也就是为了减少创建线程重复利用线程而设计的。

2. TaskScheduler

当一个Task需要运行时,首先需要添加到TaskScheduler类的一个队列中排队,TaskScheduler会从队列中取Task,放到线程中执行,默认情况下的TaskScheduler会将Task放到线程池中的线程上运行。

Task.Start和Task.ContinueWith都包含了可以传入TaskScheduler参数的版本,利用这个参数可以控制Task在哪个线程上运行。

以下我们创建了一个自己的TaskScheduler类,在TaskScheduler类中创建一条单独的线程用来执行Task。

class MyTaskScheduler : TaskScheduler
{
    public static new TaskScheduler Current { get; } = new MyTaskScheduler();
    public static new TaskScheduler Default { get; } = Current;

    private readonly BlockingCollection<Task> m_queue =   new BlockingCollection<Task>();

    MyTaskScheduler()
    {
        Thread thread = new Thread(Run);
        thread.isbackground = true;//设为为后台线程,当主线程结束时线程自动结束
        thread.Start();
    }

    private void Run()
    {
        console.WriteLine($"MyTaskScheduler, ThreadID: {Thread.CurrentThread.ManagedThreadId}");
        Task t;
        while (m_queue.TryTake(out t, Timeout.Infinite))
        {
            TryExecuteTask(t);//在当前线程执行Task
        }
    }

    protected override IEnumerable<Task> GetscheduledTasks()
    {
        return m_queue;
    }

    protected override void QueueTask(Task task)
    {
        m_queue.Add(task);//t.Start(MyTaskScheduler.Current)时,将Task加入到队列中
    }

    //当执行该函数时,程序正在尝试以同步的方式执行Task代码
    protected override bool TryExecuteTaskinline(Task task, bool taskWaspreviouslyQueued)
    {
        return false;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"Main, ThreadID: {Thread.CurrentThread.ManagedThreadId}");

        for (int i = 0; i < 10; i++)
        {
            var t = new Task(() =>
            {
                Console.WriteLine($"Task, ThreadID: {Thread.CurrentThread.ManagedThreadId}");
            });

            t.Start(MyTaskScheduler.Current);
        }
        Console.ReadKey();
    }
}

运行结果:

3. TaskScheduler与await关键字

以下是一个使用了await的函数:

        static async Task<int> fun()
        {
            await AsyncFun();

            Run();
        }

​

这函数执行的代码和以下代码类似:

Task t = AsyncFun();
var currentcontext = SynchronizationContext.Current;

if (null  == currentContext)
{
    t.ContinueWith((te) => { Run(); }, TaskScheduler.Current);
}
else
{
    t.ContinueWith((te) => { Run(); }, TaskScheduler.FromCurrentSynchronizationContext());
}

函数会先获取SynchronizationContext.Current对象,这个对象默认情况下,在控制台程序中为null,在GUI程序中不为null。当SynchronizationContext.Current==null时会直接将后续代码当作一个Task在TaskScheduler.Current上运行,如果不等于null,则会将代码在如下TaskScheduler.FromCurrentSynchronizationContext()上。

在GUI程序中SynchronizationContext.Current对象的Post方法和Send方法可以发送一段代码给主线程执行,对于函数TaskScheduler.FromCurrentSynchronizationContext返回值实际上其内部会调用Post方法,将代码发送到主线程执行,这样主线程调用的函数使用了await,函数await后面的代码依然会在主线程执行,可以防止其他线程调用主线程UI控件而崩溃。

扩展阅读

在控制台程序中使用SynchronizationContext对象

  • Await, SynchronizationContext, and Console APPs: Part 1
  • Await, SynchronizationContext, and Console Apps: Part 2
  • Await, SynchronizationContext, and Console Apps: Part 3

.Net异步编程

相关阅读

C#菜单和工具栏之contextMenuStrip、menuStrip、statu

1、contextmenustrip:上下文菜单(鼠标右键菜单) 2、menustrip:普通(窗体)菜单 3、statusStrip状态栏 4、toolStrip工具栏,可导入ico图标

C#对XML的基本操作

今天这篇文章主要讲一下用C#如何实现对XML文件的基本操作,如:创建xml文件,增、删、改、查xml的节点信息。所使用的方法很基础,方便易

C#中backgroundworker的使用

介绍: 根据MSDN介绍: BackgroundWorker 类允许您在单独的专用线程上运行操作。 耗时的操作(如下载和数据库事务)在长时间运行时可能

C#利用Picturebox控件显示图片

源文章:https://blog.csdn.net/liyuqian199695/article/details/54098938 C#利用Picturebox控件显示图片 1、Picturebox控件SizeM

C#调用WebKit内核

系统要求 Windows与.NET框架 由于WebKit库和.NET框架的要求,WebKit .NET只能在Windows系统上运行。从版本0.4开始,最低要求包

分享到:

栏目导航

推荐阅读

热门阅读