我的目标是创建一个产生初始任务数量的系统(完全相同)。这些任务将抓取并执行一些后台操作(来自数据库)然后返回,此时新任务应该生成并执行相同的操作。
我已经编写了以下代码作为概念证明,但似乎我的所有任务都是逐个执行,而不是并行执行。
代码:
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cts;
private async void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
int reqNumberOfThreads = int.Parse(textBox1.Text);
try
{
await startSlaves(cts.Token, reqNumberOfThreads);
}
catch (OperationCanceledException)
{
MessageBox.Show("Canceled Starting Threads");
}
cts = null;
}
async Task startSlaves(CancellationToken ct, int threadNum)
{
List<Task<int>> allTasks = new List<Task<int>>();// ***Add a loop to process the tasks one at a time until none remain.
for (int x = 0; x < threadNum; x++)
{
allTasks.Add(beginSlaveOperation(ct, x));
}
// ***Add a loop to process the tasks one at a time until none remain.
while (allTasks.Count <= threadNum)
{
// Identify the first task that completes.
Task<int> output = await Task.WhenAny(allTasks);
allTasks.Remove(output);
allTasks.Add(beginSlaveOperation(ct, output.Result));
}
}
public void performExampleImportOperationThread(int inputVal, int whoAmI)
{
System.Threading.Thread.Sleep(inputVal*10);
System.Console.Write("Thread number" + whoAmI.ToString() + "has finished after "+inputVal.ToString()+" secs \n");
}
async Task<int> beginSlaveOperation(CancellationToken ct, int whoAmI)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);//Get command from microSched and remove it from sched
performExampleImportOperationThread(randomNumber, whoAmI);//perform operation
return whoAmI;
}
private void button2_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
输出:
Thread number0has finished after 29 secs Thread number1has finished after 45 secs Thread number2has finished after 59 secs Thread number0has finished after 39 secs Thread number1has finished after 13 secs Thread number2has finished after 44 secs Thread number0has finished after 21 secs Thread number1has finished after 62 secs Thread number2has finished after 62 secs Thread number0has finished after 25 secs Thread number1has finished after 86 secs Thread number2has finished after 10 secs Thread number0has finished after 4 secs Thread number1has finished after 24 secs Thread number2has finished after 84 secs Thread number0has finished after 73 secs Thread number1has finished after 19 secs Thread number2has finished after 72 secs Thread number0has finished after 82 secs
答案 0 :(得分:1)
您的beginSlaveOperation
被标记为async
,并且您将其称为异步,但实际上您从未await
进行任何操作,因此它将同步运行。 (这使得调用程序同步运行,调用程序同步运行,依此类推,以便整个应用程序同步运行。)
标记方法async
并不会让它在新线程中运行。它只是让您使用await
关键字。如果您没有使用它,那么您所做的就是同步执行一堆代码并将结果包装在已完成的任务中。您甚至应该收到编译器警告。
您可以通过performExampleImportOperationThread
成为async
方法来解决此问题,而不是使用Thread.Sleep(...)
,而是使用await Task.Delay(...)
。等待performExampleImportOperationThread
使beginSlaveOperation
实际上是异步的。
或者您可以不执行您正在执行的所有操作,并通过调用Parallel.For
替换所有内容,MaxDegreesOfParallelism
可以设置{{1}}以限制您到特定数量的并发线程。< / p>
答案 1 :(得分:0)
以下是未来参考的固定代码:
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cts;
private async void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
int reqNumberOfThreads = int.Parse(textBox1.Text);
try
{
await startSlaves(cts.Token, reqNumberOfThreads);
}
catch (OperationCanceledException)
{
MessageBox.Show("Canceled Starting Threads");
}
cts = null;
}
async Task startSlaves(CancellationToken ct, int threadNum)
{
List<Task<int>> allTasks = new List<Task<int>>();// ***Add a loop to process the tasks one at a time until none remain.
for (int x = 0; x < threadNum; x++)
{
allTasks.Add(beginSlaveOperation(ct, x));
}
// ***Add a loop to process the tasks one at a time until none remain.
while (allTasks.Count <= threadNum)
{
// Identify the first task that completes.
Task<int> output = await Task.WhenAny(allTasks);
allTasks.Remove(output);
allTasks.Add(beginSlaveOperation(ct, output.Result));
}
}
public async Task performExampleImportOperationThread(int inputVal, int whoAmI)
{
await Task.Delay(inputVal*100);
System.Console.Write("Thread number" + whoAmI.ToString() + "has finished after "+inputVal.ToString()+" secs \n");
}
async Task<int> beginSlaveOperation(CancellationToken ct, int whoAmI)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);//Get command from microSched and remove it from sched
await performExampleImportOperationThread(randomNumber, whoAmI);//perform operation
return whoAmI;
}
private void button2_Click(object sender, EventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}