[C#] Task.CompletedTask和Task.Result什么时候用?

[C#] Task.CompletedTask和Task.Result什么时候用?

在学习C#中的Task方法时,可以知道Task启动一个异步线程方法可以用Task.Run()进行,具体可以参看附录部分。

但是,在有些返回类型是Task的方法中,可以在不进行异步的情况下计算结果. 比如 一个简短的计算函数,或者测试中返回一个预先计算的结果。像这种就不需要使用Task.Run,也就是说不需要异步执行.

但是它返回的又是Task类型,那应该怎么做到呢?是这样的:

对于返回是Task类型的 => 我们可以返回 Task.CompletedTask

对于返回是Task类型的 => 我们可以用Task.FromResult()来进行,比如返回的是Task类型,我们可以类似这样返回Task.FromResult("this is result");

我们来看具体的2个例子:

1. 返回Task类型

代码语言:javascript代码运行次数:0运行复制public Task Do()

{

//逻辑代码

Task.CompletedTask;

}2. 返回Task类型

代码语言:javascript代码运行次数:0运行复制public Task DoString()

{

//逻辑代码

return TasK.FromResult("This is test result");

}这2种方式,由于方法时间很短,并不需要异步执行。可以避免用Task.Run()启动异步线程导致的系统开销。

到此结束,下文是Task介绍。

附录。

简介:Task 对象是一种的中心思想基于任务的异步模式首次引入.NET Framework 4 中。 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以使用Status属性,并将IsCanceled, IsCompleted,和IsFaulted属性,以确定任务的状态。

回到顶部

一.Task的创建1.创建Task类(1)

代码语言:javascript代码运行次数:0运行复制Task task = new Task(() =>

{

Console.WriteLine("hello world!");

});

task.Start();(2)

代码语言:javascript代码运行次数:0运行复制new Task(() =>

{

Console.WriteLine("hello world!");

}).Start();(3)带参数

代码语言:javascript代码运行次数:0运行复制new Task(x =>

{

Console.WriteLine(x.ToString());

}, "hello world!").Start();(4)带返回值

代码语言:javascript代码运行次数:0运行复制Task t = new Task(x =>

{

return x.ToString();

}, "hello world!");

t.Start();

Console.WriteLine(t.Result);2.Task.Factory.StartNew(1)

代码语言:javascript代码运行次数:0运行复制Task.Factory.StartNew(() =>

{

Console.WriteLine("hello world!");

});(2)带参数

代码语言:javascript代码运行次数:0运行复制Task.Factory.StartNew(x =>

{

Console.WriteLine(x.ToString());

}, "hello world!");(3)带返回值

代码语言:javascript代码运行次数:0运行复制Task t = Task.Factory.StartNew(() =>

{

return "hello world!";

});
Console.WriteLine(t.Result);3.Task.Run代码语言:javascript代码运行次数:0运行复制Task.Run(() =>

{

Console.WriteLine("hello world!");

});4.TaskStatus代码语言:javascript代码运行次数:0运行复制Created = 0, //该任务已初始化,但尚未被计划。

WaitingForActivation = 1, //该任务正在等待 .NET Framework 基础结构在内部将其激活并进行计划。

WaitingToRun = 2,//该任务已被计划执行,但尚未开始执行。

Running = 3, //该任务正在运行,但尚未完成。

WaitingForChildrenToComplete = 4,//该任务已完成执行,正在隐式等待附加的子任务完成。

RanToCompletion = 5,//已成功完成执行的任务。

Canceled = 6, //该任务已通过对其自身的 CancellationToken 引发 OperationCanceledException 对取消进行了确认,此时该标记处于已发送信号状态;或者在该任务开始执行之前,已向该任务的CancellationToken 发出了信号。有关详细信息,请参阅任务取消。

Faulted = 7 //由于未处理异常的原因而完成的任务。二. TaskCreationOptions Task.Factory.StartNew和创建Task类可以带TaskCreationOptions参数;

而Task.Run不可以带

代码语言:javascript代码运行次数:0运行复制//// 摘要:// 指定应使用默认行为。None = 0,//// 摘要:// 提示 System.Threading.Tasks.TaskScheduler 以一种尽可能公平的方式安排任务,这意味着较早安排的任务将更可能较早运行,而较晚安排运行的任务将更可能较晚运行。PreferFairness = 1,//// 摘要:// 指定任务将是长时间运行的、粗粒度的操作,涉及比细化的系统更少、更大的组件。它会向 System.Threading.Tasks.TaskScheduler// 提示,过度订阅可能是合理的。可以通过过度订阅创建比可用硬件线程数更多的线程。它还将提示任务计划程序:该任务需要附加线程,以使任务不阻塞本地线程池队列中其他线程或工作项的向前推动。LongRunning = 2,//// 摘要:// 指定将任务附加到任务层次结构中的某个父级。默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。可以使用 System.Threading.Tasks.TaskContinuationOptions.AttachedToParent// 选项以便将父任务和子任务同步。请注意,如果使用 System.Threading.Tasks.TaskCreationOptions.DenyChildAttach// 选项配置父任务,则子任务中的 System.Threading.Tasks.TaskCreationOptions.AttachedToParent 选项不起作用,并且子任务将作为分离的子任务执行。// 有关详细信息,请参阅附加和分离的子任务。AttachedToParent = 4,//// 摘要:// 指定任何尝试作为附加的子任务执行(即,使用 System.Threading.Tasks.TaskCreationOptions.AttachedToParent// 选项创建)的子任务都无法附加到父任务,会改成作为分离的子任务执行。有关详细信息,请参阅附加和分离的子任务。DenyChildAttach = 8,//// 摘要:// 防止环境计划程序被视为已创建任务的当前计划程序。这意味着像 StartNew 或 ContinueWith 创建任务的执行操作将被视为 System.Threading.Tasks.TaskScheduler.Default// 当前计划程序。HideScheduler = 161. LongRunning任务是长时间任务,就需要用LongRunning,可能会创建一个非线程池线程来执行该任务,防止阻塞线程池队列中的其他线程

代码语言:javascript代码运行次数:0运行复制private static void fun8()

{

Task.Factory.StartNew(() =>

{

Console.WriteLine($"task1.线程 id {Thread.CurrentThread.ManagedThreadId}. 是否为线程池线程: {Thread.CurrentThread.IsThreadPoolThread}");

});

Task.Factory.StartNew(() =>

{

Console.WriteLine($"task2.线程 id {Thread.CurrentThread.ManagedThreadId}. 是否为线程池线程: {Thread.CurrentThread.IsThreadPoolThread}");

}, TaskCreationOptions.LongRunning);

} 运行结果:

2. 父子任务(AttachedToParent,DenyChildAttach)AttachedToParent:将子任务附加到父任务上,表现为:附加到父任务上的所有子任务都结束,父任务才结束

DenyChildAttach:不允许子任务附加到父任务上

(1)子任务不附加到父任务

代码语言:javascript代码运行次数:0运行复制private static void fun5()

{

Task t = Task.Factory.StartNew(() =>

{

Console.WriteLine("parent");

Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

Console.WriteLine("child");

});

});

t.ContinueWith(x =>

{

Console.WriteLine("parent over");

});

} 运行结果:

(2)子任务附加到父任务上,使用AttachedToParent

代码语言:javascript代码运行次数:0运行复制private static void fun6()

{

Task t = Task.Factory.StartNew(() =>

{

Console.WriteLine("parent");

Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

Console.WriteLine("child");

},TaskCreationOptions.AttachedToParent);

});

t.ContinueWith(x =>

{

Console.WriteLine("parent over");

});

} 运行结果:

(3)拒绝子任务附加到父任务上,使用DenyChildAttach

代码语言:javascript代码运行次数:0运行复制private static void fun7()

{

Task t = Task.Factory.StartNew(() =>

{

Console.WriteLine("parent");

Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

Console.WriteLine("child");

}, TaskCreationOptions.AttachedToParent);

}, TaskCreationOptions.DenyChildAttach);

t.ContinueWith(x =>

{

Console.WriteLine("parent over");

});

} 运行结果:

回到顶部

三.CancellationToken 取消任务代码语言:javascript代码运行次数:0运行复制private static void fun4()

{

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

CancellationToken Token = cancellationTokenSource.Token;

//结束任务回调

Token.Register(() =>

{

Console.WriteLine("canceled");

});

Task.Factory.StartNew(() =>

{

try

{

while (true)

{

Console.WriteLine("hello world!");

Thread.Sleep(100);

Token.ThrowIfCancellationRequested();

}

}

catch (OperationCanceledException ocex)

{

}

catch (ObjectDisposedException odex)

{

}

catch (Exception ex)

{

}

}, Token);

Thread.Sleep(1000);

cancellationTokenSource.Cancel();

}执行结果:

当执行cancellationTokenSource.Cancel()后,任务进行到Token.ThrowIfCancellationRequested()代码后,throw出OperationCanceledException异常,才结束任务并执行cancel回调

或者在while循环里使用

代码语言:javascript代码运行次数:0运行复制if (Token.IsCancellationRequested)

return;回到顶部

四.方法Wait

等待 System.Threading.Tasks.Task 完成执行过程

WaitAll

等待提供的所有 System.Threading.Tasks.Task 对象完成执行过程

WaitAny

等待提供的任一 System.Threading.Tasks.Task 对象完成执行过程

WhenAll

创建一个任务,该任务将在所有 System.Threading.Tasks.Task 对象都完成时完成

WhenAny

任何提供的任务已完成时,创建将完成的任务

ContinueWith

创建一个在目标 System.Threading.Tasks.Task 完成时异步执行的延续任务

1 Wait阻塞当前线程,等待任务执行完成代码语言:javascript代码运行次数:0运行复制//等待 System.Threading.Tasks.Task 在指定的毫秒数内完成执行。

public bool Wait(int millisecondsTimeout);

//等待 System.Threading.Tasks.Task 完成执行过程。如果在任务完成之前取消标记已取消,等待将终止。

public void Wait(CancellationToken cancellationToken);

//等待 System.Threading.Tasks.Task 完成执行过程。如果在任务完成之前超时间隔结束或取消标记已取消,等待将终止。

public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken);

//等待 System.Threading.Tasks.Task 完成执行过程。

public void Wait();

//等待 System.Threading.Tasks.Task 在指定的时间间隔内完成执行。

public bool Wait(TimeSpan timeout);使用方式:

代码语言:javascript代码运行次数:0运行复制t.Wait();//无限等待

t.Wait(100);//等待100ms

t.Wait(TimeSpan.FromMilliseconds(1500));//等待1500ms例:

代码语言:javascript代码运行次数:0运行复制private static void fun9()

{

Task t = Task.Factory.StartNew(() =>

{

Thread.Sleep(1000);

Console.WriteLine("task");

});

t.Wait();

Console.WriteLine("main");

} 运行结果:

2.WaitAll 阻塞当前线程,等待所有任务执行完成代码语言:javascript代码运行次数:0运行复制//等待提供的所有 System.Threading.Tasks.Task 对象完成执行过程。

public static void WaitAll(params Task[] tasks);

//等待所有提供的可取消 System.Threading.Tasks.Task 对象在指定的时间间隔内完成执行。

public static bool WaitAll(Task[] tasks, TimeSpan timeout);

//等待所有提供的 System.Threading.Tasks.Task 在指定的毫秒数内完成执行。

public static bool WaitAll(Task[] tasks, int millisecondsTimeout);

//等待提供的所有 System.Threading.Tasks.Task 对象完成执行过程(除非取消等待)。

public static void WaitAll(Task[] tasks, CancellationToken cancellationToken);

//等待提供的所有 System.Threading.Tasks.Task 对象在指定的毫秒数内完成执行,或等到取消等待。

public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken); 使用:

代码语言:javascript代码运行次数:0运行复制private static void fun10()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

});

//Task.WaitAll(t1, t2);

//Task.WaitAll(new Task[] { t1, t2 }, 200);

Task.WaitAll(new Task[] { t1, t2 }, TimeSpan.FromMilliseconds(200));

Console.WriteLine("main");

} 运行结果:

3.WaitAny阻塞当前线程,等待任一任务执行完成代码语言:javascript代码运行次数:0运行复制//等待提供的任一 System.Threading.Tasks.Task 对象完成执行过程。

public static int WaitAny(params Task[] tasks);

//等待任何提供的 System.Threading.Tasks.Task 对象在指定的时间间隔内完成执行。

public static int WaitAny(Task[] tasks, TimeSpan timeout);

//等待任何提供的 System.Threading.Tasks.Task 对象在指定的毫秒数内完成执行。

public static int WaitAny(Task[] tasks, int millisecondsTimeout);

//等待提供的任何 System.Threading.Tasks.Task 对象完成执行过程(除非取消等待)。

public static int WaitAny(Task[] tasks, CancellationToken cancellationToken);

//等待提供的任何 System.Threading.Tasks.Task 对象在指定的毫秒数内完成执行,或等到取消标记取消。

public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken); 使用:

代码语言:javascript代码运行次数:0运行复制private static void fun11()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

});

//Task.WaitAny(t1, t2);

//Task.WaitAny(new Task[] { t1, t2 }, 200);

Task.WaitAny(new Task[] { t1, t2 }, TimeSpan.FromMilliseconds(200));

Console.WriteLine("main");

} 结果:

4.WhenAll不阻塞当前线程,等待所有任务执行完成后,可以进行ContinueWith代码语言:javascript代码运行次数:0运行复制//创建一个任务,该任务将在可枚举集合中的所有 System.Threading.Tasks.Task 对象都完成时完成。

public static Task WhenAll(IEnumerable tasks);

//创建一个任务,该任务将在数组中的所有 System.Threading.Tasks.Task 对象都完成时完成。

public static Task WhenAll(params Task[] tasks);

//创建一个任务,该任务将在可枚举集合中的所有 System.Threading.Tasks.Task`1 对象都完成时完成。

public static Task WhenAll(IEnumerable> tasks);

//创建一个任务,该任务将在数组中的所有 System.Threading.Tasks.Task`1 对象都完成时完成。

public static Task WhenAll(params Task[] tasks); 使用:

(1)不带返回值

代码语言:javascript代码运行次数:0运行复制public static Task WhenAll(params Task[] tasks);代码语言:javascript代码运行次数:0运行复制private static void fun12()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

});

Task.WhenAll(t1, t2).ContinueWith(t =>

{

Console.WriteLine("WhenAll");

});

Console.WriteLine("main");

} 执行结果:

(2)带返回值

代码语言:javascript代码运行次数:0运行复制public static Task WhenAll(params Task[] tasks);代码语言:javascript代码运行次数:0运行复制private static void fun13()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

return "task1";

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

return "task2";

});

Task.WhenAll(new Task[] { t1, t2 }).ContinueWith(t =>

{

string s = "WhenAll:";

foreach (string item in t.Result)

{

s += item;

}

Console.WriteLine(s);

});

Console.WriteLine("main");

} 执行结果:

5.WhenAny代码语言:javascript代码运行次数:0运行复制//任何提供的任务已完成时,创建将完成的任务。

public static Task WhenAny(params Task[] tasks);

//任何提供的任务已完成时,创建将完成的任务。

public static Task WhenAny(IEnumerable tasks);

//任何提供的任务已完成时,创建将完成的任务。

public static Task> WhenAny(params Task[] tasks);

//任何提供的任务已完成时,创建将完成的任务。

public static Task> WhenAny(IEnumerable> tasks); 使用:

(1)不带参数

代码语言:javascript代码运行次数:0运行复制public static Task WhenAny(params Task[] tasks);代码语言:javascript代码运行次数:0运行复制private static void fun14()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

});

Task.WhenAny(t1, t2).ContinueWith(t =>

{

Console.WriteLine("WhenAny1");

});

Console.WriteLine("main");

} 运行结果:

(2)带参数:

代码语言:javascript代码运行次数:0运行复制public static Task> WhenAny(params Task[] tasks);代码语言:javascript代码运行次数:0运行复制private static void fun15()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(100);

Console.WriteLine("task1");

return "response task1";

});

Task t2 = Task.Factory.StartNew(() =>

{

Thread.Sleep(150);

Console.WriteLine("task2");

return "response task2";

});

Task.WhenAny(new Task[] { t1, t2 }).ContinueWith(t =>

{

t.Result.ContinueWith(tt =>

{

Console.WriteLine(tt.Result);

});

});

Console.WriteLine("main");

}运行结果:

6.ContinueWith相当于回调

6.1使用(1)使用lambda表达式方式

代码语言:javascript代码运行次数:0运行复制private static void fun1()

{

Console.WriteLine("start");

Task task1 = new Task(() =>

{

Console.WriteLine("task0");

return "task1";

});

Task task2 = task1.ContinueWith(t =>

{

Console.WriteLine(t.Result);

return "task2";

});

task1.Start();

Console.WriteLine("end");

Console.ReadKey();

}2.使用函数

代码语言:javascript代码运行次数:0运行复制private static void fun2()

{

Console.WriteLine("start");

Task task1 = new Task(doTask1);

Task task2 = task1.ContinueWith(doTask2);

task1.Start();

Console.WriteLine("end");

Console.ReadKey();

}

private static string doTask1()

{

Console.WriteLine("task0");

return "task1";

}

private static string doTask2(Task t)

{

Console.WriteLine(t.Result);

return "task2";

} 运行结果:

6.2 ContineWith和task可能不在同一线程上例:

代码语言:javascript代码运行次数:0运行复制private static void fun16()

{

Task.Factory.StartNew(() =>

{

Console.WriteLine($"task {Thread.CurrentThread.ManagedThreadId}");

}).ContinueWith(t =>

{

Console.WriteLine($"ContinueWith {Thread.CurrentThread.ManagedThreadId}");

});

} 运行结果:

回到顶部

七.TaskFactory类方法:

StartNew

创建并启动任务

ContinueWhenAll

创建一个延续任务,该任务在一组指定的任务完成后开始

ContinueWhenAny

创建一个延续 System.Threading.Tasks.Task,它将在提供的组中的任何任务完成后马上开始

FromAsync

创建一个 System.Threading.Tasks.Task`1,表示符合异步编程模型模式的成对的开始和结束方法

1.ContinueWhenAll相当于回调

效果其实和WhenAll差不多,只不过ContineWhenAll采用了回调的方式

使用:带返回值

代码语言:javascript代码运行次数:0运行复制private static void fun17()

{

Task t1 = Task.Factory.StartNew(() =>

{

Console.WriteLine("task1");

return "task1";

});

Task t2 = Task.Factory.StartNew(() =>

{

Console.WriteLine("task2");

return "task2";

});

Task.Factory.ContinueWhenAll(new Task[] { t1, t2 }, t =>

{

string s = "ContinueWhenAll:";

foreach (Task item in t)

{

s += item.Result;

}

Console.WriteLine(s);

});

} 运行结果:

2.ContinueWhenAny相当于回调

效果其实和WhenAny差不多,只不过ContineWhenAny采用了回调的方式

使用:

代码语言:javascript代码运行次数:0运行复制private static void fun18()

{

Task t1 = Task.Factory.StartNew(() =>

{

Thread.Sleep(10);

Console.WriteLine("task1");

return "task1";

});

Task t2 = Task.Factory.StartNew(() =>

{

Console.WriteLine("task2");

return "task2";

});

Task.Factory.ContinueWhenAny(new Task[] { t1, t2 }, t =>

{

Console.WriteLine($"{(t as Task).Result} 先执行完");

});

} 执行结果:

3.FromAsync相当于异步委托的精简写法,其中ContinueWith相当于异步委托中的callback

使用:

public Task FromAsync(Func beginMethod, Func endMethod, TArg1 arg1, object state);

代码语言:javascript代码运行次数:0运行复制static void Main(string[] args)

{

fun20();

Console.WriteLine("Main");

Console.ReadKey();

}

private static void fun20()

{

var func = new Func(x =>

{

Thread.Sleep(1000);

Console.WriteLine(x);

return "callback";

});

Task.Factory.FromAsync(func.BeginInvoke, func.EndInvoke, "func", null).ContinueWith(t =>

{

Console.WriteLine(t.Result);

});

} 运行结果:

相关推荐

国内优秀的广告联盟有哪些?
365的账户被关闭

国内优秀的广告联盟有哪些?

📅 07-03 👁️ 2894
冰箱开启后多久制冷0
网上365不给提款的解决办法

冰箱开启后多久制冷0

📅 06-30 👁️ 1946
DNF服务器全球开服时间表大全
网上365不给提款的解决办法

DNF服务器全球开服时间表大全

📅 07-02 👁️ 6711