我可以将Task.Run包装在另一个Task.Run()下吗?

时间:2014-02-10 11:29:06

标签: c# multithreading asynchronous task-parallel-library

我有一个方法HandleAcceptedConnection,它位于Task.Run()下,我想异步运行(在另一个单独的线程中)。我尝试将HandleAcceptedConnection声明为async方法并且不调用await但它似乎不是异步运行。我可以确认我可以在另一个Task.Run()下拥有Task.Run()(通过观察线程ID),但这是推荐的吗?

private async void Start_Click(object sender, RoutedEventArgs e)
{
        var task = Task.Run(() =>
        {
            while (isContinue)
            {
                var handler = listener.Accept();
                // handle connection

                Log("Before");
                Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId);

                // i want to run method below asynchronously. i want to 
                // wrap it under Task.Run() but i am already under 
                // Task.Run(). i set HandleAcceptedConnection as async. i thought by not 
                // calling await on HandleAcceptedConnection, HandleAcceptedConnection 
                // is asynchronous
                HandleAcceptedConnection(handler); 

                Log("After");

                isContinue = true;
            }
        });
        await task;
}

private async Task HandleAcceptedConnection(Socket handler)
{
    Log("ThreadId HandleAcceptedConnection " + Thread.CurrentThread.ManagedThreadId);
    Log("Under HandleAcceptedConnection");
    Thread.Sleep(10000);   
}

当我运行时,日志说

Before
Under HandleAcceptedConnection
After

我想要

Before
After
Under HandleAcceptedConnection

我希望HandleAcceptedConnection以异步方式运行。我应该将它包装在另一个Task.Run下还是已经异步?

2 个答案:

答案 0 :(得分:2)

你试过吗

private async Task HandleAcceptedConnection(Socket handler)
{
    Thread.Sleep(1000);
    Log("Under HandleAcceptedConnection");
}

因为在另一个线程上做某事并不意味着它会被延迟。

答案 1 :(得分:1)

您应该使用AcceptTcpClientAsync,那么您将不需要额外的线程。请查看this answer以获取示例。当有可用的自然异步版本时,请不要使用同步API。

已更新以解决评论。没有什么可以阻止您在Task.Run内使用Task.Run,您的代码可能看起来像这样(未经测试):

private async void Start_Click(object sender, RoutedEventArgs e)
{
    var connectionTasks = new List<Task>();

    Func<Task> handleConnection = async () =>
    {
        var connectionTask = Task.Run(() => HandleAcceptedConnection(handler));
        connectionTasks.Add(connectionTask);
        await connectionTask;
        connectionTasks.Remove(connectionTask);
    };

    var task = Task.Run(() =>
    {
        while (isContinue)
        {
            var handler = listener.Accept();
            // handle connection

            Log("Before");
            Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId);

            var connectionTask = handleConnection();

            Log("After");

            isContinue = true;
        }
    });
    await task;
}