我已经读过有关async-await模式的信息,并且Mutex
与异步代码不兼容,所以我想知道如何以轻量级的方式编写以下方法,没有对象分配(甚至不是Task<>
)但没有过多的责任(来自模式)。
问题如下。看看这个方法:
public async void SendAsync(Stream stream, byte[] data)
{
await stream.WriteAsync(data.Length);
await stream.WriteAsync(data);
await stream.FlushAsync();
}
现在,这种方法可能不是很有用。事实上,有更多的代码,但对于手头的问题,它是完全完整的。
这里的问题是我有一个主线程,可以在没有await
的情况下快速调用该方法:
for (i = 0; i < 10; i++)
{
SendAsync(stream[i], buffer[i]);
}
我想要的只是主线程快速循环而不会阻塞。
现在,这个循环也循环了:
while (true)
{
for (i = 0; i < 10; i++)
{
SendAsync(stream[i], buffer[i]);
}
// TODO: add a break criterion here
}
我怀疑(恐惧)是在拥挤的buffer
(是的,它下面的TCP / IP stream[i]
)上有一个非常厚实的NetworkStream
(比如1 MB)导致n
th 调用在前面的n-1
th 调用可重入(从调用返回)之前发生
这两项任务将相互干扰。
我不想要我已经丢弃的这两种解决方案中的任何一种:
这将引发异常,因为Mutex
具有线程关联性,而异步代码与线程无关:
public async void SendAsync(Stream stream, byte[] data)
{
mutex.WaitOne(); // EXCEPTION!
await stream.WriteAsync(data.Length);
await stream.WriteAsync(data);
await stream.FlushAsync();
mutex.ReleaseMutex();
}
Task
返回*.WaitAll()
循环在消费者的土地上,而SendAsync()
在框架土地上,我不想强迫消费者使用错综复杂的模式:
while (true)
{
for (i = 0; i < 10; i++)
{
tasks[i] = SendAsync(stream[i], buffer[i]);
}
Task.WaitAll(tasks);
// TODO: add a break criterion here
}
此外,我绝对不希望在每个循环上分配Task
,此代码将以中等频率(5-10 Hz)运行,具有1000多个开放流。我不能每秒分配10000多个对象,它会像GC一样疯狂。请注意,这是每个SO策略的最小代码,实际代码要复杂得多。
我希望看到的是某种外循环分配,只有在绝对必要时才会等待完成(例如Mutex
)但是同一时间不会在循环内部分配内存。
答案 0 :(得分:2)
假设你有一个关于流的包装类,你可以这样做:
private Stream stream;
private Task currentTask;
public async void SendAsync(byte[] data)
{
currentTask = WriteAsyncWhenStreamAvailable(data);
await currentTask;
}
private async Task WriteAsyncWhenStreamAvailable(byte[] data)
{
if (currentTask != null)
await currentTask.ConfigureAwait(false);
await WriteAsync(data);
}
public async Task WriteAsync(byte[] data)
{
await stream.WriteAsync(data.Length).ConfigureAwait(false);
await stream.WriteAsync(data).ConfigureAwait(false);
await stream.FlushAsync().ConfigureAwait(false);
}
这样,您始终可以在发送新数据之前等待之前的WriteAsync
结束。此解决方案将确保以请求的顺序发送缓冲区。
您可以使用async SemaphoreSlim
代替Mutex
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
public async void SendAsync(Stream stream, byte[] data)
{
await semaphore.WaitAsync(); // EXCEPTION!
await stream.WriteAsync(data.Length);
await stream.WriteAsync(data);
await stream.FlushAsync();
semaphore.Release();
}
请注意OutOfMemoryException
如果您在不考虑待处理缓冲区大小的情况下无盲地生成新数据...