Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# a-同步并行任务的正确方法_C#_.net_Async Await_Task Parallel Library - Fatal编程技术网

C# a-同步并行任务的正确方法

C# a-同步并行任务的正确方法,c#,.net,async-await,task-parallel-library,C#,.net,Async Await,Task Parallel Library,目前,我们有一个工作正常的代码: Result result1 = null; Result result2 = null; var task1 = Task.Factory.StartNew(()=> { var records = DB.Read(".."); //Do A lot result1 = Process(records); }); var task2 = Task.Factory.StartNew(()=> { var record

目前,我们有一个工作正常的代码:

Result result1 = null;
Result result2 = null;

var task1 = Task.Factory.StartNew(()=>
{
   var records = DB.Read("..");
   //Do A lot
   result1 = Process(records);  
}); 

var task2 = Task.Factory.StartNew(()=>
{
   var records = DB.Read(".....");
   //Do A lot
   result2 = Process(records);  
});

Task.WaitAll(task1, task2);

var result = Combine(result1, result2);
现在,我们想使用DB函数的异步对应项,我们正在使用这种新模式:

Result result1 = null;
Result result2 = null;

var task1 = await Task.Factory.StartNew( async ()=>
{
   var records = await DB.ReadAsync("..");
   //Do A lot
   result1 = Process(records);  
}); 

var task2 = await Task.Factory.StartNew(async ()=>
{
   var records = await DB.ReadAsync(".....");
   //Do A lot
   result2 = Process(records);  
});

Task.WaitAll(task1, task2);

var result = Combine(result1, result2);

切换到异步后,我们开始观察异常行为。所以我想知道这是否是并行异步调用的正确模式

Task.Factory.StartNew
是一个预异步API。您应该使用
Task.Run
,它的设计考虑了异步等待:

var task1 = await Task.Run( async ()=>
{
   var records = await DB.ReadAsync("..");
   //Do A lot
   result1 = Process(records);  
});
问题是异步lambda返回一个
任务
so
任务.Factory.StartNew
返回一个
任务
(外部lambda是因为
任务.Factory.StartNew
返回一个
任务
,内部lambda是异步lambda的结果)

这意味着,当您等待
task1
task2
时,您实际上并不是在等待整个操作,而是等待其中的同步部分

您可以通过在返回的
任务上使用
任务。展开


您只需要
任务。如果需要将这些方法的同步部分(第一个
等待
之前的部分)卸载到
线程池
启动另一个独立执行单元的新执行任务,则只需运行
。因此,最简单的处理方法可能是:

var task1 = Task.Factory.StartNew(()=> //NO AWAIT
{
   var records = DB.Read("....."); //NO ASYNC
   //Do A lot
   result1 = Process(records);  
});

... another task definition

Task.WaitAll(task1, task2);

在一个任务中按顺序读取和处理,因为您具有数据依赖性

很好地使用.WaitAll不是异步编程,因为您实际上是在等待时阻塞当前线程。另外,您也不调用.Unwrap,这就是为什么您只需等待异步lambda的创建,而不等待异步lambda本身

Task.Run可以为您展开异步lambda。但是有一种更简单更干净的方法

var task1 = DB.ReadAsync("..").ContinueWith(task => {
   //Do A lot
   return Process(task.Result);  
}, TaskScheduler.Default);

var task2 = DB.ReadAsync("..").ContinueWith(task => {
   //Do A lot
   return Process(task.Result);  
}, TaskScheduler.Default);

var result = Combine(await task1, await task2);
这样,当它准备好时,您将得到准确的结果。因此,您根本不需要额外的任务和变量

请注意,ContinueWith是一个复杂的函数,它在TaskScheduler上工作。如果它不为null,则为Current,否则它在TaskScheduler上工作。默认值为线程池调度器。因此,在调用此函数时,始终显式指定调度程序更安全


同样对于claryfing,我没有包括错误检查,因为实际上DB.ReadAsync可以通过一个错误来完成。但这很容易,你可以自己处理。

你具体说的是什么样的异常行为?这些任务相互交织在一起了吗?任务是否工作不正常?您的
结果应该是任务返回值,而不是闭包变量。从任务中返回它们。我猜task1/2上等待的方法将立即返回,这可能被称为异常。基本上,我无法遍历调试中的代码。突然间,代码流启动并完成了整个过程,出现了错误您不应该在task1=wait上添加wait。我们认为这就是问题的原因。为什么不直接使用
await DB.ReadAsync()
而不使用
Task。运行
wrappers?@nosratio:对,您仍然可以。但是,看起来Op更关心的是使用
任务
,出于某种原因,然后是异步调用。@Tigran,我会使用异步API而不包装,然后用
任务包装
过程
调用。运行
-如果它们真的是CPU密集型的话。@nosratio:我的观点是:旋转
任务
(线程)相对来说是epxnsive操作,考虑到您需要以任何方式(因为它是计算密集型的),只需提前完成即可。更直接的数据管理。@您可以将它们声明为委托,然后调用它们,但它不太干净:
Func action1=async()=>。。。;任务task1=action1()
ContinueWith
中的参数是antecedent
Task
。StartNew不支持异步方法,它不打开内部任务。您真的应该使用
Task.Run(
)来代替。请阅读Stepen ClearI的“”不要使用异步方法,如果您阅读代码,您可能会看到。
var task1=Task.Factory.StartNew(异步()=>
您就在那里使用async。
task1
将是一个
任务
,您的
WaitAll
不会像您期望的那样工作。要想像您希望的那样使用
WaitAll
,您首先需要在任务上调用
.Unwrap()
(或者使用
Task.Run(
,它会为您调用Unwrap)@ScottChamberlain你说得对。用手机写代码和错误的代码复制/粘贴。我肯定不是这么想的。
var task1 = Task.Factory.StartNew(()=> //NO AWAIT
{
   var records = DB.Read("....."); //NO ASYNC
   //Do A lot
   result1 = Process(records);  
});

... another task definition

Task.WaitAll(task1, task2);
var task1 = DB.ReadAsync("..").ContinueWith(task => {
   //Do A lot
   return Process(task.Result);  
}, TaskScheduler.Default);

var task2 = DB.ReadAsync("..").ContinueWith(task => {
   //Do A lot
   return Process(task.Result);  
}, TaskScheduler.Default);

var result = Combine(await task1, await task2);