gpt4 book ai didi

c# - 如何取消自定义等待

转载 作者:行者123 更新时间:2023-12-03 11:59:09 25 4
gpt4 key购买 nike

我已阅读 Stephen Toub's blog关于为 SocketAsyncEventArgs 制作自定义等待。这一切正常。但我需要的是一个可取消的等待对象,并且该博客不涉及这个主题。不幸的是,Stephen Cleary 也没有在他的书中介绍如何取消不支持取消的异步方法。
我尝试自己实现它,但我因 TaskCompletionSource 和 Task.WhenAny 失败,因为使用可等待的我实际上并没有等待任务。
这就是我想要的:能够使用带有 TAP 格式的 Socket 的 ConnectAsync 并能够取消它,同时仍然具有 SocketAsyncEventArgs 的可重用性。

public async Task ConnectAsync(SocketAsyncEventArgs args, CancellationToken ct) {}

到目前为止,这就是我从 Stephen Toub 的博客中获得的内容(以及 SocketAwaitable 实现):
public static SocketAwaitable ConnectAsync(this Socket socket,
SocketAwaitable awaitable)
{
awaitable.Reset();
if (!socket.ConnectAsync(awaitable.m_eventArgs))
awaitable.m_wasCompleted = true;
return awaitable;
}

我只是不知道如何将其转换为 TAP 格式并使其可取消。
任何帮助表示赞赏。

编辑 1:
这是我如何正常取消的示例:

private static async Task<bool> ConnectAsync(SocketAsyncEventArgs args, CancellationToken cancellationToken)
{
var taskCompletionSource = new TaskCompletionSource<bool>();

cancellationToken.Register(() =>
{TaskCompletionSource.Task
taskCompletionSource.TrySetCanceled();
});

// This extension method of Socket not implemented yet
var task = _socket.ConnectAsync(args);

var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);

return await completedTask;
}

最佳答案

custom awaitable for SocketAsyncEventArgs.



这是可行的,但是 SocketAsyncEventArgs专门用于对性能极为敏感的场景。绝大多数(我的意思是 >99.9%)项目不需要它,可以使用 TAP 代替。 TAP 很好,因为它可以与其他技术很好地互操作……比如取消。

what I need is a cancellable awaitable and the blog doesn't cover this topic. Also Stephen Cleary unfortunately doesn't cover in his book how to cancel async methods that don't support cancellation.



所以,这里有几件事。从“如何取消不支持取消的异步方法”开始:简短的回答是你不能。这是因为取消是合作的;所以如果一方不能合作,那就不可能了。更长的答案是它是可能的,但通常比它的值(value)更多的麻烦。

在“取消不可取消的方法”的一般情况下,您可以在单独的线程上同步运行该方法,然后中止该线程;这是最有效和最危险的方法,因为中止的线程很容易破坏应用程序状态。为了避免这种严重的损坏问题,最可靠的方法是在单独的进程中运行该方法,该进程可以干净地终止。然而,这通常是矫枉过正,而且比它的值(value)更多的麻烦。

足够的一般性答案;特别是对于套接字,您不能取消单个操作,因为这会使套接字处于未知状态。采取 Connect您的问题中的示例:连接和取消之间存在竞争条件。您的代码在请求取消后可能会以连接的套接字结束,并且您不希望该资源保留。所以取消套接字连接的正常和公认的方法是关闭套接字。

任何其他套接字操作也是如此:如果您需要中止读取或写入,那么当您的代码发出取消时,它无法知道读取/写入完成了多少 - 这将使套接字处于未知状态说明您正在使用的协议(protocol)。 The proper way to "cancel" any socket operation is to close the socket .

请注意,此“取消”的范围与我们通常看到的取消类型不同。 CancellationToken和好友代表取消单次操作;关闭套接字会取消该套接字的所有操作。因此,套接字 API 不采用 CancellationToken参数。

Stephen Cleary unfortunately doesn't cover in his book how to cancel async methods that don't support cancellation. I tried to implement it myself



“我如何取消一个不可取消的方法”这个问题几乎从来没有用“使用这个代码块”来解决。具体来说,您使用的方法取消了等待,而不是操作。请求取消后,您的应用程序仍在尝试连接到服务器,并且最终可能成功或失败(两个结果都将被忽略)。

在我的 AsyncEx 库中,我确实有一个 couple WaitAsync 重载,它允许您执行以下操作:
private static async Task MyMethodAsync(CancellationToken cancellationToken)
{
var connectTask = _socket.ConnectAsync(_host);
await connectTask.WaitAsync(cancellationToken);
...
}

我更喜欢这种 API,因为很明显取消的是异步等待,而不是连接操作。

I fail with the TaskCompletionSource and Task.WhenAny because with the awaitable I'm not actually awaiting a task.



好吧,要执行这样更复杂的操作,您需要将 awaitable 转换为 Task .可能有一个更有效的选择,但这真的很麻烦。即使你弄清楚了所有的细节,你仍然会得到“假取消”:一个看起来像是取消操作但实际上并没有取消的 API——它只是取消了等待。

This is what I would like to have: being able to use Socket's ConnectAsync with TAP format and being able to cancel it, while still having the reusability of SocketAsyncEventArgs.



TL;DR:您应该关闭套接字而不是取消连接操作。就快速回收资源而言,这是最干净的方法。

关于c# - 如何取消自定义等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59209996/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com