什么';现代的C#方式是启动两个线程,然后等待它们结束吗?
您将如何使用C#中最新的线程技术重写此代码 加载程序和提取对象都有一个什么';现代的C#方式是启动两个线程,然后等待它们结束吗?,c#,multithreading,C#,Multithreading,您将如何使用C#中最新的线程技术重写此代码 加载程序和提取对象都有一个Start方法: public Thread Start() { var thread = new Thread(Extract); thread.Start(); return thread; } 任务: var t1 = Task.Factory.StartNew(() => extracter.Start(), TaskCreationOptions.LongRunning); var
Start
方法:
public Thread Start()
{
var thread = new Thread(Extract);
thread.Start();
return thread;
}
任务:
var t1 = Task.Factory.StartNew(() => extracter.Start(), TaskCreationOptions.LongRunning);
var t2 = Task.Factory.StartNew(() => loader.Start(), TaskCreationOptions.LongRunning);
// some arbitrary amount of code here that's executed on the main thread.
// Wait for both threads to complete before continuing.
t1.Wait();
t2.Wait();
// Code here cannot execute until the loader and extractor are finished.
与显式管理线程相比,任务有许多特性使其更易于使用,包括支持取消、继续等。非常值得研究。使用此定义的方法:
async Task<TResult> RunLoadAsync(/* args */) {
var dateRange = new DateRange(date, date.AddDays(1));
var extracter = new ConversionsExtracter(dateRange, AdvertiserId);
var loader = new ConversionsLoader();
var intermediate = await Task.Factory.StartNew(
() => extracter.Start(), TaskCreationOptions.LongRunning
);
return await Task.Factory.StartNew(
() => loader.Start(intermediate), TaskCreationOptions.LongRunning
);
}
更新:下面是一个更完整的用法示例:
private async void PanelBoard_MouseCtlClick(object sender, HexEventArgs e) {
GoalHex = e.Coords;
// other processing to prepare.
try { Path = await MapBoard.GetDirectedPathAsync(MapBoard[StartHex], MapBoard[GoalHex]); }
catch (OperationCanceledException) { Path = default(IDirectedPath); }
}
public static async Task<IDirectedPath> GetDirectedPathAsync(
this IBoard<IHex> @this,
IHex start, IHex goal
) {
if (@this == null) throw new ArgumentNullException("this");
return @this.GetDirectedPath(start, goal);
}
IDirectedPath Path {
set { /* code here to refresh display when Path is ready */ }
}
public static Task<IDirectedPath> GetDirectedPathAsync(
this IBoard<IHex> @this,
IHex start, IHex goal
) {
if (@this == null) throw new ArgumentNullException("this");
return Task.Run<IDirectedPath>(
() => @this.GetDirectedPath(start, goal)
);
}
private async void PanelBoard\u MouseCtlClick(对象发送方,HexEventArgs e){
GoalHex=e.Coords;
//其他加工准备。
请尝试{Path=await MapBoard.GetDirectedPathAsync(MapBoard[StartHex],MapBoard[GoalHex]);}
catch(OperationCanceledException){Path=default(IDirectedPath);}
}
公共静态异步任务GetDirectedPathAsync(
这个IBoard@this,
IHex开始,IHex目标
) {
如果(@this==null)抛出新的ArgumentNullException(“this”);
返回@this.GetDirectedPath(开始,目标);
}
IDirectedPath路径{
在此处设置{/*代码,以便在路径就绪时刷新显示*/}
}
公共静态任务GetDirectedPathAsync(
这个IBoard@this,
IHex开始,IHex目标
) {
如果(@this==null)抛出新的ArgumentNullException(“this”);
返回任务。运行(
()=>@this.GetDirectedPath(开始,目标)
);
}
方法GetDirectedPathAsync()上的async限定符使其成为Wait的对象 “最新线程技术”指的是.NET 4.x中的
异步
/等待
和任务
功能吗?我想是的。。我开始阅读它,只是不完全清楚它是传统线程的替代品,还是只在某些情况下适用。也许可以看看吧?那不对-这两个都是阻塞调用,所以主线程将阻塞到完成。@PieterGeerkens:是的,主线程阻塞,直到两个线程都完成。它与OP显示的行为完全相同,只需使用Task
。我假设他通过消除主线程在这两个线程进行处理时所做的处理来简化事情。在第一次调用Wait
之前,可能会发生很多事情,但是主线程必须确保其他线程都完成了,然后才能继续。也许我的编辑给了你一个更好的主意?我更喜欢Task.WhenAll(t1,t2).Wait()
,如果t1
抛出,它将允许捕获两个任务的异常。由于只创建一个而不是两个要阻止的同步对象,所以它的成本可能会低一些。如果您仍然要阻止,我会说Task.WaitAll(t1,t2)
。另外,您应该使用Task.Run
或显式地将调度程序传递给StartNew
,RunLoadAsync
将在此处同步完成。仅仅输入一个async
关键字并不能创建并发。@CoryNelson:这就是为什么要使用wait关键字异步调用它,如上所示。RunLoadAsync()
将阻止并返回一个完全完成的任务。然后,wait
将立即完成。从字面上看,就好像您只是直接调用了RunLoad()
,但却增加了大量开销,使行为完全没有变化——这里没有异步。要解释的是:async
方法是100%同步的(即它们与调用方在同一线程中执行)在他们点击等待
之前,不要返回任务
。在RunLoadAsync
中使用wait
之前,除了方法的结果将被包装在任务
中之外,没有任何更改<代码>等待不会异步调用某些内容。wait
在调用方法后发生。引入异步是被调用方的(RunLoadAsync
)作业,而调用方的作业(带有wait
)则是等待(可能是异步的,也可能不是)任务完成。更好。另请参见Task.Run
,了解短期任务。它比Task.Factory.StartNew
更高效,但不提供提示它将长期运行的功能。
var result = await RunLoadAsync(/* parameters */);
private async void PanelBoard_MouseCtlClick(object sender, HexEventArgs e) {
GoalHex = e.Coords;
// other processing to prepare.
try { Path = await MapBoard.GetDirectedPathAsync(MapBoard[StartHex], MapBoard[GoalHex]); }
catch (OperationCanceledException) { Path = default(IDirectedPath); }
}
public static async Task<IDirectedPath> GetDirectedPathAsync(
this IBoard<IHex> @this,
IHex start, IHex goal
) {
if (@this == null) throw new ArgumentNullException("this");
return @this.GetDirectedPath(start, goal);
}
IDirectedPath Path {
set { /* code here to refresh display when Path is ready */ }
}
public static Task<IDirectedPath> GetDirectedPathAsync(
this IBoard<IHex> @this,
IHex start, IHex goal
) {
if (@this == null) throw new ArgumentNullException("this");
return Task.Run<IDirectedPath>(
() => @this.GetDirectedPath(start, goal)
);
}