我正在编写一个类似于这个的代码(我在stackoverflow上修改了它,所以可能它有拼写错误)我有些疑惑。
PacketType.Rename
和PacketType.GetName
之后,它可能会结束,在更新GetName()
上的值之前发送Rename()
结果。我应该在任何方法之前在两个方法上使用锁定对象
逻辑确保"命令"?我可以假设BeginReceive()
任务
在等待Rename()
被调用之前,不会开始阅读下一条消息
因此,Rename()
内的第一行应始终锁定
在代码从PacketType.GetName
获取之前调用
NetworkStream
,拨打执行并致电等待GetName()
?PacketType.Rename
一起发送10次,将获得一个数据包
在BeginReceive()
上按一个,运行Execute()
然后返回以获取下一个
一旦代码等待Rename()
,就可以使用Rename()
方法
在多个任务中同时运行。如果我不在乎
哪一个是像这种情况更新值的最新一个(全部
重命名是相同的),或更新的值与a不相关
姓名,我应该关心吗?MockConnectionHandler
作为注入属性的单个服务实例应该没问题?每个任务应该使这些独立于运行相同服务/存储库的其他任务吗?public class Listener : IListener
{
public string Name {get;set;}
public int Connected {get;set;}
...
private async Task Listen()
{
while (!_Token.IsCancellationRequested)
{
tcpClient = await _Listener.AcceptTcpClientAsync().ConfigureAwait(false);
Connected++;
IConnectionHandler connectionHandler = _ClientPool.Receive();
connectionHandler.TcpClient = tcpClient;
connectionHandler.Listener = this; // really is done on the Listener init()
connectionHandler.Init();
}
}
}
public class MockConnectionHandler : IConnectionHandler
{
public string Name {get;set;}
public int Messages {get;set;}
public IListener Listener {get;set;}
public void Init()
{
BeginReceive();
}
private void BeginReceive()
{
var receive = Task.Run(async () =>
{
while (true)
{
readedHeader = await _Stream.ReadAsync(dataHead, 0, headerLength, _DisconnectToken);
// get body length from header.
readedBody = await _Stream.ReadAsync(dataBody, 0, bodyLength, _DisconnectToken);
Task run = Task.Run(() => Execute(headType, dataBody));
}
}, _DisconnectToken)
.ContinueWith(previous =>
{
_EndReceiving = true;
}, TaskContinuationOptions.OnlyOnCanceled);
}
private async Task Execute(PacketType type, byte[] data)
{
switch(packetType)
{
case PacketType.Echo:
await SendAsync(new Bag(PacketType.Echo));
case PacketType.Rename:
await Rename();
case PacketType.GetName:
await GetName();
}
}
private async Task Rename(byte[] data)
{
Name = Encoding.UTF8.GetString(data);
Listener.Name = Encoding.UTF8.GetString(data);
}
private async Task GetName()
{
byte[] data = Encoding.UTF8.GetBytes(Name);
SendAsync(new Bag(PacketType.Echo, data));
}
}
答案 0 :(得分:1)
如果你等待每个异步函数就像你正在做的那样,代码将同步运行"但是潜在地减少了延迟。如果你可以并行执行某些操作,那么等待每个异步方法都是不好的,而是保存Task句柄,稍后当你需要所有任务的结果时等待一系列任务。
即。如果你有asyncMeth1()和asyncMeth2(),并且它们不相互依赖/可以并行运行,你不应该单独等待每一个,而是保存Task对象并在以后当你真正需要时等待它们两者的结果。
答案 1 :(得分:0)
任何时候你在任务上调用等待代码都会返回给调用者。一旦任务完成,它就会发出信号,然后代码返回到那个时间点。
只有在您选择不对每项任务使用等待时,这才会变得棘手。如果您在没有等待的情况下运行任务,那么该任务将与您的代码并行运行,作为单独的线程。如果等待该任务,则返回调用者。
无论其;回答我认为你问...返回调用者不会在等待之前返回任务..它返回到链中的第一个等待调用。例如:如果你有一个等待某个任务的方法,那么该方法的调用者可以自由继续运行...在那里等待是否有另一个内部等待然后没有,你的第一个await不会启动并继续。这些任务像使用等待时的队列一样被链接在一起。
→ caller continues executing
caller → method → await task1 → await task2 → await task3
↓
task3 complete
↓
cont task2 ← -------
↓
task2 complete
↓
cont task1 ← ------
↓
task1 complete
↓
cont method ← -----
↓
method complete
↓
(nothing to do)
值得一提的是,在任务中跳过await关键字的任何地方,它都会成为链中该点的调用者。