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异步编程
- parallel Programming with .NET
相关阅读
C#菜单和工具栏之contextMenuStrip、menuStrip、statu
1、contextmenustrip:上下文菜单(鼠标右键菜单) 2、menustrip:普通(窗体)菜单 3、statusStrip状态栏 4、toolStrip工具栏,可导入ico图标
今天这篇文章主要讲一下用C#如何实现对XML文件的基本操作,如:创建xml文件,增、删、改、查xml的节点信息。所使用的方法很基础,方便易
介绍: 根据MSDN介绍: BackgroundWorker 类允许您在单独的专用线程上运行操作。 耗时的操作(如下载和数据库事务)在长时间运行时可能
源文章:https://blog.csdn.net/liyuqian199695/article/details/54098938 C#利用Picturebox控件显示图片 1、Picturebox控件SizeM
系统要求 Windows与.NET框架 由于WebKit库和.NET框架的要求,WebKit .NET只能在Windows系统上运行。从版本0.4开始,最低要求包