我有50个机器学习代理。每一帧,他们得到一些输入并计算神经网络。因为每个代理都是独立的,所以我想让每个代理将网络计算为一个单独的任务。
如果我要为每个代理创建一个任务,每个帧,它将使我的程序更慢。我试图将我的代理分为两个任务(25和25),但它仍然是一个开销。
我看到它的方式是在开始时为n组代理创建n个线程,并以某种方式查询每个帧的那些线程。线程将计算代理组的网络,然后等到下一个查询。
我已经阅读了一些关于这个主题的文章,我发现我无法重用任务。那么,哪种解决方法可以起作用?
基本上,我对50个代理程序进行了重复操作,每个框架运行一次,大约一分钟,并且不会并行化它们是浪费。
我仍然是多线程和任务的新手,所以我依靠你的帮助。
<小时/> 附注:我在Unity中使用遗传算法。 下面是我试图将代理分成n组并在n个任务中计算其网络的代码。
public async Task EvaluateAsync(int groupSize = 10)
{
var groups = genomes.Select((g, i) => new { Value = g, Index = i })
.GroupBy(x => x.Index / groupSize)
.Select(x => x.Select(v => v.Value));
var tasks = groups.Select(g =>
{
return Task.Run(() =>
{
foreach (var element in g)
element.Fitness += ComputeFitness(element as NeuralGenome);
});
}).ToArray();
for (var i = 0; i < tasks.Length; i++)
await tasks[i];
}
在我调用的Update()
函数中:
EvaluateAsync(25).Wait();
当网络非常大时,它会快一点,但只有10个神经元时速度要慢得多。
只有在网络非常庞大的情况下,使组变小,才能获得更好的性能。
这里我为每个代理创建一个任务:
public async Task EvaluateAsyncEach()
{
var tasks = genomes.Select(x => Task.Run(() => x.Fitness += ComputeFitness(x as NeuralGenome)))
.ToArray();
foreach (var task in tasks)
await task;
}
对10帧进行以下测量。意思是,t / 10将是一个任务的时间。
正常运行的时间:
00:00:00.3791190
00:00:00.3758430
00:00:00.3697020
00:00:00.3743900
00:00:00.3764850
每个代理每个代理一个任务:
00:00:01.1288240
00:00:01.0761770
00:00:00.9311210
00:00:01.0122570
00:00:00.8938200
以25人为一组:
00:00:00.5401100
00:00:00.5629660
00:00:00.5640470
00:00:00.5932220
00:00:00.6053940
00:00:00.5828170
答案 0 :(得分:0)
这是一篇很好的文章。
http://fintechexplained.blogspot.com/2018/05/top-ten-tips-for-implementing-multi.html?m=1
您的解决方案是PLINQ。避免创建新任务
答案 1 :(得分:0)
您应该使用Microsoft的Reactive Framework来实现此目的。它非常适合这种处理。
以下是代码:
var query =
from genome in genomes.ToObservable()
from fitness in Observable.Start(() => ComputeFitness(genome as NeuralGenome))
select new { genome, fitness };
IDisposable subscription =
query.Subscribe(x => x.genome.Fitness += x.fitness);
它完成了所有自己的线程/任务管理。它在计算时也会尽快产生结果。
如果您希望能够await
结果,您可以这样做:
var query =
from genome in genomes.ToObservable()
from fitness in Observable.Start(() => ComputeFitness(genome as NeuralGenome))
select new { genome, fitness };
var results = await query.ToArray();
foreach (var x in results)
{
x.genome.Fitness += x.fitness;
}
Just NuGet&#34; System.Reactive&#34;并在查询中添加using System.Reactive.Linq;
。
根据评论中的代码,我认为你应该看一下这个:
private async Task ComputingNetworksAsync()
{
var query =
from a in agents.ToObservable()
let i = a.GenerateNetworkInputs()
from n in Observable.Start(() => a.ComputeNetwork(i))
select n;
await query.ToArray();
}
这相当于您的代码(.ToArray()
除外)。
但是,您可以更进一步,并执行此操作:
private async Task ComputingNetworksAsync()
{
var query =
from a in agents.ToObservable()
from i in Observable.Start(() => a.GenerateNetworkInputs())
from n in Observable.Start(() => a.ComputeNetwork(i))
select n;
await query.ToArray();
}