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

C# 我可以将Task.Run包装到另一个Task.Run()下吗?,c#,multithreading,asynchronous,task-parallel-library,C#,Multithreading,Asynchronous,Task Parallel Library,我有一个HandleAcceptedConnection方法,它位于Task.Run()下,我想异步运行(在另一个单独的线程中)。我尝试将HandleAcceptedConnection声明为异步方法,并且不调用wait,但它似乎不是异步运行的。我可以确认我可以将Task.Run()放在另一个Task.Run()下(通过查看线程id),但建议这样做吗 private async void Start_Click(object sender, RoutedEventArgs e) {

我有一个HandleAcceptedConnection方法,它位于Task.Run()下,我想异步运行(在另一个单独的线程中)。我尝试将HandleAcceptedConnection声明为异步方法,并且不调用wait,但它似乎不是异步运行的。我可以确认我可以将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下,还是它已经是异步的

你试过了吗

private async Task HandleAcceptedConnection(Socket handler)
{
    Thread.Sleep(1000);
    Log("Under HandleAcceptedConnection");
}
因为在另一个线程上执行某些操作并不意味着它将被延迟。

您应该使用,这样您就不需要额外的线程。请查看示例。当有同步API的自然异步版本可用时,不要使用同步API

已更新以处理评论。没有任何东西阻止您使用
任务。从
任务内部运行
。运行
,您的代码可能如下所示(未测试):

private async void Start\u单击(对象发送方,路由目标)
{
var connectionTasks=新列表();
Func handleConnection=async()=>
{
var connectionTask=Task.Run(()=>HandleAcceptedConnection(handler));
connectionTasks.Add(connectionTask);
等待连接任务;
connectionTasks.Remove(connectionTask);
};
var task=task.Run(()=>
{
while(isContinue)
{
var handler=listener.Accept();
//手柄连接
日志(“之前”);
日志(“ThreadId接受”+Thread.CurrentThread.ManagedThreadId);
var connectionTask=handleConnection();
日志(“之后”);
isContinue=true;
}
});
等待任务;
}

您的方法将同步运行,因为它不包含
wait
语句。但即使它是异步运行的,这也意味着您根本无法保证“After”和“Under”的顺序将出现在中。如果需要“After”显示在“Under”之前,只需将方法调用移到末尾。您在这里想要实现什么?我认为您需要更深入地阅读async/await/Tasks。需要理解的主要内容是:async/await/Task不一定等于多线程。@Jon“Before”“Before”“Under”“Before”只是指示HandleaceptedConnection是同步运行还是异步运行的名称。了解HandleAcceptedConnection是否异步运行的更好方法是监视线程(我刚刚添加的)。我只想从“上面的调用者”在另一个线程/async中运行HandleAcceptedConnection。@Public敌手现在替换
thread.Sleep(10000)等待任务。延迟(10000)并重试。顺便说一句:在登录之前使用它,可以看到它将在执行该操作的L.B之后运行。我还将Thread.CurrentThread.ManagedThreadId放在Task.Delay()前后,似乎Task.Delay()前后使用了不同的线程。似乎Task.Delay()导致该方法使用不同的线程。最好使用
Task.Delay()
-它不会因为阻塞线程而浪费线程。然后你必须等待它-否则首先让方法
异步
就没有多大意义了。@Krumelur不仅更好。他/她必须使用
等待任务。延迟(1000)
以获得所需的效果。@L.B我不明白他想解决什么问题,所以我不确定所需的效果是什么:-)@Krumelur OP不想完全等待
HandleAcceptedConnection
。如果他不想等待,为什么一开始就让它异步呢?我想说的是:询问者试图解决一些听起来没有被正确思考的问题,这是对多线程、ATPL、同步和异步代码的误解和混合。我使用的网络库中没有AcceptTcpClientAsync。事实上,在我使用的网络库中,所有公开的方法都是同步的。你应该在你的问题中澄清这一点。我现在回忆起还有一个问题,您提到了一个第三方套接字,比如支持异步的库,但明天我就不记得了:)哈哈,对不起。我不想提及关于套接字或网络的任何内容,因为问题实际上是关于异步的东西。@public敌手,没问题。注意,只有在lambda内部使用
await
时,才需要在lambda之前使用
async
。@public敌方,实际上,在您的情况下,每个新连接都意味着一个新的池线程,因此您不应该
等待
任务的结果。运行
。不过,您仍然需要跟踪连接。我已经更新了答案,以说明如何才能做到这一点。
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;
}