C# 我可以将Task.Run包装到另一个Task.Run()下吗?
我有一个HandleAcceptedConnection方法,它位于Task.Run()下,我想异步运行(在另一个单独的线程中)。我尝试将HandleAcceptedConnection声明为异步方法,并且不调用wait,但它似乎不是异步运行的。我可以确认我可以将Task.Run()放在另一个Task.Run()下(通过查看线程id),但建议这样做吗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) {
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;
}