如何异步运行3个进程,当其中一个返回所需值时,停止其他两个进程并继续执行程序
本文关键字:进程 其他 执行程序 继续 两个 返回 何异步 3个 运行 一个 异步 | 更新日期: 2023-09-27 18:26:00
我有一个方法,它使用aferge.net框架对屏幕的一个区域模板化(检查一个图像与另一个图像的相似性)多个单独的图像。这项任务可能需要很长时间,也可能几乎是即时的,具体取决于图像的数量、图像的大小和检查的区域。
图像列表中只有一个图像会返回匹配,所以我想同时在屏幕上测试所有图像,当这些图像中的1个返回真值时,剩余的过程将立即取消,我的程序将进入下一步。
现在,在我给出的例子中,我正在获取一个整数值,根据该整数值匹配将返回true,但概念始终相同。。x根据屏幕截图测试的图像数量。。1将返回true,其余将不返回。有时第一个返回true,过程又好又快,其他时候是列表中的第30个,与1相比,同步匹配30个图像的模板需要相当长的时间。
关于下面的代码,需要注意一点。。我不会总是返回一个整数,我通常会返回一个布尔值,说明找到了哪个图像,但这里的代码最容易详细说明,同样的一般原理也适用(即:如果我能用一种方法计算出来,我就能用另一种方法)。
目前我的(同步)代码如下。。。我该如何使这个异步调用能够实现我所描述的功能?如果可能的话,请详细说明你的答案,因为我打算学习,这样我将来就可以很容易地做这类事情。我理解异步的概念,但由于某种原因,我无法完全理解如何按照我想要的方式进行。
public void Battle()
{
var myGuysTurn = WhosTurn();
// other logic here.
}
private int WhosTurn()
{
var whosTurn = 0;
var whosTurnCheck = _templateMatch.Match(_tabula.BattleHeroTurn1());
if (whosTurnCheck)
{
whosTurn = 1;
return whosTurn;
}
whosTurnCheck = _templateMatch.Match(_tabula.BattleHeroTurn2());
if (whosTurnCheck)
{
whosTurn = 2;
return whosTurn;
}
whosTurnCheck = _templateMatch.Match(_tabula.BattleHeroTurn3());
if (whosTurnCheck)
{
whosTurn = 3;
return whosTurn;
}
return whosTurn;
}
我会将Task.WaitAny()
与CancellationToken
结合使用。从本质上讲,并行启动每个任务,并等待任何任务完成。如果已完成的任务成功,请取消其他任务。如果没有,请继续等待其他任务完成。
为了简洁起见,我用静态方法BattleHeroTurnX
替换了_templateMatch.Match(_tabula.BattleHeroTurnX())
:
private int WhosTurn()
{
// Create cancellation token. Will be used to inform other threads that they should immediately cancel processing
CancellationTokenSource cts = new CancellationTokenSource();
// Collection of tasks that run in parallel
List<Task<int>> tasks = new List<Task<int>>()
{
Task.Run<int>(() => {
return BattleHeroTurn1(cts.Token) ? 1 : 0;
}),
Task.Run<int>(() => {
return BattleHeroTurn2(cts.Token) ? 2 : 0;
}),
Task.Run<int>(() => {
return BattleHeroTurn3(cts.Token) ? 3 : 0;
})
};
// Wait for any task to complete and if it is successful, cancel the other tasks and return
while (tasks.Any())
{
// Get the index of the task that completed
int completedTaskIndex = Task.WaitAny(tasks.ToArray());
int turn = tasks[completedTaskIndex].Result;
if(turn > 0)
{
cts.Cancel();
return turn;
}
tasks.RemoveAt(completedTaskIndex);
}
// All tasks have completed but no BattleHeroTurnX returned true
return 0;
}
static bool BattleHeroTurn1(CancellationToken token)
{
// Processing images. After each one is processed, ensure that the token has not been canceled
for(int i = 0; i < 100; i++)
{
Thread.Sleep(50);
if (token.IsCancellationRequested)
{
return false;
}
}
return true;
}
static bool BattleHeroTurn2(CancellationToken token)
{
// Processing images. After each one is processed, ensure that the token has not been canceled
for (int i = 0; i < 10; i++)
{
Thread.Sleep(70);
if (token.IsCancellationRequested)
{
return false;
}
}
return true;
}
static bool BattleHeroTurn3(CancellationToken token)
{
// Processing images. After each one is processed, ensure that the token has not been canceled
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(500);
if (token.IsCancellationRequested)
{
return false;
}
}
return true;
}
有关更多信息,请参阅此和此。