杭州.net培训
达内杭州.net培训中心

13732203138

热门课程

NETCore你知道多少

  • 时间:2019-01-17 18:02
  • 发布:转载
  • 来源:网络


如果你需要运行多个后台任务,这里有些方法可以帮助到你。 要同时运行多个任务,只需连续启动它们并收集它们的引用,例如在数组中:


var backgroundTasks = new []


{


Task.Run(() => DoComplexCalculation(1)),


Task.Run(() => DoComplexCalculation(2)),


Task。Run(() => DoComplexCalculation(3))


};


现在你可以使用Task类的静态方法,等待他们被异步或者同步执行完毕。


// wait synchronously


Task。WaitAny(backgroundTasks);


Task。WaitAll(backgroundTasks);


// wait asynchronously


await Task。WhenAny(backgroundTasks);


await Task.WhenAll(backgroundTasks);


实际上,这两个方法最终都会返回所有任务的自身,可以像任何其他任务一样再次操作。为了获取对应任务的结果,你可以检查该任务的Result属性。 处理多任务的异常有点棘手。方法WaitAllWhenAll不管哪个任务被收集到异常时都会抛出异常。


不过,对于WaitAll,将会收集所有的异常到对应的InnerExceptions属性;对于WhenAll,只会抛出第一个异常。为了确认哪个任务抛出了哪个异常,您需要单独检查每个任务的StatusException属性。 在使用WaitAnyWhenAny时必须足够小心。


他们会等到第一个任务完成(成功或失败),即使某个任务出现异常时也不会抛出任何异常。他们只会返回已完成任务的索引或者分别返回已完成的任务。


你必须等到任务完成或访问其result属性时捕获异常,例如:


var completedTask = await Task.WhenAny(backgroundTasks);


try


{


var result = await completedTask;


}


catch (Exception e)


{


// handle exception


}


如果你想连续运行多个任务,代替并发任务,可以使用延续(continuations)的方式:


var compositeTask = Task。Run(() => DoComplexCalculation(42))


。ContinueWith(previous => DoAnotherComplexCalculation(previous。Result),


TaskContinuationOptions。OnlyOnRanToCompletion)


ContinueWith()方法允许你把多个任务一个接着一个执行。这个延续的任务将获取到前面任务的结果或状态的引用。 你仍然可以增加条件判断是否执行延续任务,例如只有在前面任务成功执行或者抛出异常时。


对比连续等待多个任务,提高了灵活性。 当然,您可以将延续任务与之前讨论的所有功能相结合:异常处理、取消和并行运行任务。这就有了很大的表演空间,以不同的方式进行组合:


var multipleTasks = new[]


{


Task.Run(() => DoComplexCalculation(1)),


Task.Run(() => DoComplexCalculation(2)),


Task.Run(() => DoComplexCalculation(3))


};


var combinedTask = Task.WhenAll(multipleTasks);


var successfulContinuation = combinedTask.ContinueWith(task =>


CombineResults(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion);


var failedContinuation = combinedTask。ContinueWith(task =>


HandleError(task.Exception), TaskContinuationOptions.NotOnRanToCompletion);


await Task。WhenAny(successfulContinuation, failedContinuation);


任务同步


如果任务是完全独立的,那么我们刚才看到的协调方法就已足够。然而,一旦需要同时共享数据,为了防止数据损坏,就必须要有额外的同步。 


两个以及更多的线程同时更新一个数据结构时,数据很快就会变得不一致。就好像下面这个示例代码一样:


var counters = new Dictionary< int, int >();


if (counters.ContainsKey(key))


{


counters[key] ++;


}


else


{


counters[key] = 1;


}


当多个线程同时执行上述代码时,不同线程中的特定顺序执行指令可能导致数据不正确,例如:


·        所有线程将会检查集合中是否存在同一个key


·        结果,他们都会进入else分支,并将这个key的值设为1


·        最后结果将会是1,而不是2。如果是接连着执行代码的话,将会是预期的结果。


上述代码中,临界区(critical section)一次只允许一个线程可以进入。在C#中,可以使用lock语句来实现:


var counters = new Dictionary< int, int >();


lock (syncObject)


{


if (counters.ContainsKey(key))


{


counters[key]++;


}


else


{


counters[key] = 1;


}


}


在这个方法中,所有线程都必须共享相同的的syncObject。


作为最佳做法,syncObject应该是一个专用的Object实例,专门用于保护对一个独立的临界区的访问,避免从外部访问。 lock语句中,只允许一个线程访问里面的代码块。


它将阻止下一个尝试访问它的线程,直到前一个线程退出。这将确保线程完整执行临界区代码,而不会被另一个线程中断。


当然,这将减少并行性并减慢代码的整体执行速度,因此您最好最小化临界区的数量并使其尽可能的短。


使用Monitor类来简化lock声明:


var lockWasTaken = false;


var temp = syncObject;


try


{


Monitor。Enter(temp, ref lockWasTaken);


// lock statement body


}


finally


{


if (lockWasTaken)


{


Monitor.Exit(temp);


}


}


尽管大部分时间您都希望使用lock语句,但Monitor类可以在需要时给予额外的控制。例如,您可以使用TryEnter()而不是Enter(),并指定一个限定时间,避免无止境地等待锁释放。


预约申请免费试听课

怕钱不够?就业挣钱后再付学费!    怕学不会?从入学起,达内定制课程!     担心就业?达内多家实践企业供你挑选!

上一篇:划重点了!
下一篇:JAVA常见的算法集锦
选择城市和中心
贵州省

广西省

海南省

棋牌游戏大全 棋牌游戏大全 棋牌游戏 波克棋牌 大富豪棋牌 网络棋牌游戏 棋牌游戏大厅 三多棋牌 大富豪棋牌 网络棋牌游戏