如何在 C# 中 运行 并行和顺序方法?
How do I run a method both parallel and sequentially in C#?
我有一个 C# 控制台应用程序。在这个应用程序中,我有一个方法,我将调用 DoWorkAsync
。对于这个问题的上下文,这个方法看起来像这样:
private async Task<string> DoWorkAsync()
{
System.Threading.Thread.Sleep(5000);
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var length = random.Next(10, 101);
await Task.CompletedTask;
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
我从另一种方法调用 DoWorkAsync
,该方法确定 a) 这将获得多少次 运行 和 b) 每次调用是并行还是顺序 运行。该方法如下所示:
private async Task<Task<string>[]> DoWork(int iterations, bool runInParallel)
{
var tasks = new List<Task<string>>();
for (var i=0; i<iterations; i++)
{
if (runInParallel)
{
var task = Task.Run(() => DoWorkAsync());
tasks.Add(task);
}
else
{
await DoWorkAsync();
}
}
return tasks.ToArray();
}
所有任务完成后,我想显示结果。为此,我的代码如下所示:
var random = new Random();
var tasks = await DoWork(random.Next(10, 101);
Task.WaitAll(tasks);
foreach (var task in tasks)
{
Console.WriteLine(task.Result);
}
如果代码 运行s 并行(即 runInParallel
是 true
),此代码将按预期工作。但是,当 runInParallel
为假时(即我想按顺序 运行 任务),Task
数组不会被填充。因此,调用方没有任何结果可供使用。我不知道如何解决它。我不确定如何将方法调用添加为 Task
,它将按顺序 运行。我知道任务背后的想法是 运行 并行。但是,我需要在并行和顺序之间切换。
谢谢!
我认为您最好执行以下操作:
- 创建一个函数来创建(冷)任务列表(或数组
Task<string>[]
,例如)。不需要 运行 他们。我们称之为 GetTasks()
var jobs = GetTasks();
- 然后,如果您想“按顺序”运行它们,只需
var results = new List<string>();
foreach (var job in jobs)
{
var result = await job;
results.Add(result);
}
return results;
如果你想 运行 它们并行:
foreach (var job in jobs)
{
job.Start();
}
await results = Task.WhenAll(jobs);
另一个注释,
这一切本身应该是 Task<string[]>
,Task<Task<...
闻起来像个问题。
the Task
array doesn't get populated.
所以填充它:
else
{
var task = DoWorkAsync();
tasks.Add(task);
await task;
}
P.S.
另外你的 DoWorkAsync
在我看来有点不对,为什么 Thread.Sleep
而不是 await Task.Delay
(这是模拟异步执行的更正确的方法,你也不需要 await Task.CompletedTask
这样)。如果您希望 DoWorkAsync
被 CPU 绑定,只需将其设置为:
private Task<string> DoWorkAsync()
{
return Task.Run(() =>
{
// your cpu bound work
return "string";
});
}
之后你可以做这样的事情(对于async/cpu绑定的工作):
private async Task<string[]> DoWork(int iterations, bool runInParallel)
{
if(runInParallel)
{
var tasks = Enumerable.Range(0, iterations)
.Select(i => DoWorkAsync());
return await Task.WhenAll(tasks);
}
else
{
var result = new string[iterations];
for (var i = 0; i < iterations; i++)
{
result[i] = await DoWorkAsync();
}
return result;
}
}
为什么 DoWorkAsync
是一个 async
方法?
它目前没有做任何异步的事情。
您似乎正试图利用多线程来提高昂贵的 CPU 绑定工作的性能,因此您最好使用专为此设计的 Parallel.For
目的:
private string DoWork()
{
System.Threading.Thread.Sleep(5000);
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var length = random.Next(10, 101);
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
private string[] DoWork(int iterations, bool runInParallel)
{
var results = new string[iterations];
if (runInParallel)
{
Parallel.For(0, iterations - 1, i => results[i] = DoWork());
}
else
{
for (int i = 0; i < iterations; i++) results[i] = DoWork();
}
return results;
}
然后:
var random = new Random();
var serial = DoWork(random.Next(10, 101));
var parallel = DoWork(random.Next(10, 101), true);
我有一个 C# 控制台应用程序。在这个应用程序中,我有一个方法,我将调用 DoWorkAsync
。对于这个问题的上下文,这个方法看起来像这样:
private async Task<string> DoWorkAsync()
{
System.Threading.Thread.Sleep(5000);
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var length = random.Next(10, 101);
await Task.CompletedTask;
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
我从另一种方法调用 DoWorkAsync
,该方法确定 a) 这将获得多少次 运行 和 b) 每次调用是并行还是顺序 运行。该方法如下所示:
private async Task<Task<string>[]> DoWork(int iterations, bool runInParallel)
{
var tasks = new List<Task<string>>();
for (var i=0; i<iterations; i++)
{
if (runInParallel)
{
var task = Task.Run(() => DoWorkAsync());
tasks.Add(task);
}
else
{
await DoWorkAsync();
}
}
return tasks.ToArray();
}
所有任务完成后,我想显示结果。为此,我的代码如下所示:
var random = new Random();
var tasks = await DoWork(random.Next(10, 101);
Task.WaitAll(tasks);
foreach (var task in tasks)
{
Console.WriteLine(task.Result);
}
如果代码 运行s 并行(即 runInParallel
是 true
),此代码将按预期工作。但是,当 runInParallel
为假时(即我想按顺序 运行 任务),Task
数组不会被填充。因此,调用方没有任何结果可供使用。我不知道如何解决它。我不确定如何将方法调用添加为 Task
,它将按顺序 运行。我知道任务背后的想法是 运行 并行。但是,我需要在并行和顺序之间切换。
谢谢!
我认为您最好执行以下操作:
- 创建一个函数来创建(冷)任务列表(或数组
Task<string>[]
,例如)。不需要 运行 他们。我们称之为GetTasks()
var jobs = GetTasks();
- 然后,如果您想“按顺序”运行它们,只需
var results = new List<string>();
foreach (var job in jobs)
{
var result = await job;
results.Add(result);
}
return results;
如果你想 运行 它们并行:
foreach (var job in jobs)
{
job.Start();
}
await results = Task.WhenAll(jobs);
另一个注释,
这一切本身应该是 Task<string[]>
,Task<Task<...
闻起来像个问题。
the
Task
array doesn't get populated.
所以填充它:
else
{
var task = DoWorkAsync();
tasks.Add(task);
await task;
}
P.S.
另外你的 DoWorkAsync
在我看来有点不对,为什么 Thread.Sleep
而不是 await Task.Delay
(这是模拟异步执行的更正确的方法,你也不需要 await Task.CompletedTask
这样)。如果您希望 DoWorkAsync
被 CPU 绑定,只需将其设置为:
private Task<string> DoWorkAsync()
{
return Task.Run(() =>
{
// your cpu bound work
return "string";
});
}
之后你可以做这样的事情(对于async/cpu绑定的工作):
private async Task<string[]> DoWork(int iterations, bool runInParallel)
{
if(runInParallel)
{
var tasks = Enumerable.Range(0, iterations)
.Select(i => DoWorkAsync());
return await Task.WhenAll(tasks);
}
else
{
var result = new string[iterations];
for (var i = 0; i < iterations; i++)
{
result[i] = await DoWorkAsync();
}
return result;
}
}
为什么 DoWorkAsync
是一个 async
方法?
它目前没有做任何异步的事情。
您似乎正试图利用多线程来提高昂贵的 CPU 绑定工作的性能,因此您最好使用专为此设计的 Parallel.For
目的:
private string DoWork()
{
System.Threading.Thread.Sleep(5000);
var random = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var length = random.Next(10, 101);
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
private string[] DoWork(int iterations, bool runInParallel)
{
var results = new string[iterations];
if (runInParallel)
{
Parallel.For(0, iterations - 1, i => results[i] = DoWork());
}
else
{
for (int i = 0; i < iterations; i++) results[i] = DoWork();
}
return results;
}
然后:
var random = new Random();
var serial = DoWork(random.Next(10, 101));
var parallel = DoWork(random.Next(10, 101), true);