异步任务按顺序执行?

时间:2013-12-11 00:22:24

标签: c# multithreading

我的目标是创建一个产生初始任务数量的系统(完全相同)。这些任务将抓取并执行一些后台操作(来自数据库)然后返回,此时新任务应该生成并执行相同的操作。

我已经编写了以下代码作为概念证明,但似乎我的所有任务都是逐个执行,而不是并行执行。

代码:

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 

2 个答案:

答案 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();
        }
    }