반응형
루프에서 await를 사용하는 방법
컬렉션에서 일부 작업을 수행하는 비동기 콘솔 앱을 만들려고합니다. async / await를 사용하는 다른 버전의 루프를 병렬로 사용하는 버전이 있습니다. 비동기 / 대기 버전이 병렬 버전과 유사하게 작동 할 것으로 예상했지만 동 기적으로 실행됩니다. 내가 도대체 뭘 잘못하고있는 겁니까?
class Program
{
static void Main(string[] args)
{
var worker = new Worker();
worker.ParallelInit();
var t = worker.Init();
t.Wait();
Console.ReadKey();
}
}
public class Worker
{
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
var result = await DoWorkAsync(i);
if (result)
{
Console.WriteLine("Ending Process {0}", i);
}
}
return true;
}
public async Task<bool> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return true;
}
public bool ParallelInit()
{
var series = Enumerable.Range(1, 5).ToList();
Parallel.ForEach(series, i =>
{
Console.WriteLine("Starting Process {0}", i);
DoWorkAsync(i);
Console.WriteLine("Ending Process {0}", i);
});
return true;
}
}
await
키워드를 사용하는 방식 은 병렬이 아닌 루프를 통과 할 때마다 기다리는 것을 C #에 알려줍니다. Task
s 목록을 저장 한 다음 await
모두를 사용하여 원하는 작업을 수행하도록 메서드를 다시 작성할 수 있습니다 Task.WhenAll
.
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<Tuple<int, bool>>>();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
tasks.Add(DoWorkAsync(i));
}
foreach (var task in await Task.WhenAll(tasks))
{
if (task.Item2)
{
Console.WriteLine("Ending Process {0}", task.Item1);
}
}
return true;
}
public async Task<Tuple<int, bool>> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return Tuple.Create(i, true);
}
코드는 await
다음 반복을 시작하기 전에 각 작업 (사용 )이 완료 될 때까지 기다립니다 .
따라서 병렬 처리가 없습니다.
기존 비동기 작업을 병렬로 실행하려면 필요하지 않습니다 await
. Task
s 모음을 가져 와서 Task.WhenAll()
모두를 기다리는 작업을 반환하기 위해 호출 하면됩니다.
return Task.WhenAll(list.Select(DoWorkAsync));
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5);
Task.WhenAll(series.Select(i => DoWorkAsync(i)));
return true;
}
C # 7.0 에서는 튜플의 각 멤버에 의미 체계 이름을 사용할 수 있습니다 . 여기 에 새 구문을 사용한 Tim S. 의 대답이 있습니다.
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<(int Index, bool IsDone)>>();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
tasks.Add(DoWorkAsync(i));
}
foreach (var task in await Task.WhenAll(tasks))
{
if (task.IsDone)
{
Console.WriteLine("Ending Process {0}", task.Index);
}
}
return true;
}
public async Task<(int Index, bool IsDone)> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return (i, true);
}
때로는 copy+ paste준비 솔루션 만 있으면됩니다. 따라서 이것이 Tim.S 의 전체 솔루션입니다 . :
namespace AsyncSimple
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
class Startup
{
static void Main()
{
var worker = new Worker();
worker.ParallelInit();
var t = worker.Init();
t.Wait();
Console.ReadKey();
}
}
public class Worker
{
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<Tuple<int, bool>>>();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
tasks.Add(DoWorkAsync(i));
}
foreach (var task in await Task.WhenAll(tasks))
{
if (task.Item2)
{
Console.WriteLine("Ending Process {0}", task.Item1);
}
}
return true;
}
public async Task<Tuple<int, bool>> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return Tuple.Create(i, true);
}
public bool ParallelInit()
{
var series = Enumerable.Range(1, 5).ToList();
Parallel.ForEach(series, i =>
{
Console.WriteLine("Starting Process {0}", i);
DoWorkAsync(i);
Console.WriteLine("Ending Process {0}", i);
});
return true;
}
}
}
그리고 콘솔의 결과 :
참고 URL : https://stackoverflow.com/questions/19431494/how-to-use-await-in-a-loop
반응형
'Programing' 카테고리의 다른 글
C ++에서 비어있는 std :: shared_ptr의 차이점은 무엇입니까? (0) | 2020.10.20 |
---|---|
jquery에서 추가와 반대 (0) | 2020.10.19 |
AngularJs에 숨겨진 가시성? (0) | 2020.10.19 |
SQL Server에서 십진 열의 정밀도를 어떻게 변경합니까? (0) | 2020.10.19 |
IEnumerable.Intersect ()를 사용하여 여러 목록의 교차 (0) | 2020.10.19 |