使用StreamWriter异步时,出现错误“该流上的操作当前正在使用该流”

时间:2019-03-20 10:37:06

标签: c# async-await semaphore streamwriter

我有一组任务,这些任务获取要尝试协调到流中的字符串。一切看起来不错,但实际上我得到了

  

该流的先前操作当前正在使用该流

Task.WhenAll通话之后。

示例:

    private readonly List<Task<string>> _objectData = new List<Task<string>>();
    private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);

    private async Task SafelyWrite(StreamWriter streamWriter, string field)
    {
        await _writerSemaphore.WaitAsync();

        if (field.IsNullOrWhiteSpace())
        {
            return;
        }

        streamWriter.Write(field);

        await streamWriter.FlushAsync();

        _writerSemaphore.Release();
    }

    public override async Task Build(StreamWriter streamWriter)
    {
        streamWriter.Write('{');

        await Task.WhenAll(
            _objectData.Select(async str => SafelyWrite(streamWriter, await str)));

        // await Task.Delay(10);

        // If I don't wait for a few milliseconds the app
        // will throw an error on this line that the stream
        // is currently being written to?
        streamWriter.Write('}');

        await streamWriter
            .FlushAsync();
    }

如果我查看流的内容,则有无延迟都有效。一切都完成了,仅仅是StreamWriter认为还没有?如果我等待几毫秒,StreamWriter认为一切都已完成,那么我可以编写结束代码了。

Task.WhenAllSemaphoreSlim之间是否缺少我想要的东西?

(很抱歉,代码量最少,示例似乎很失败,但很有用)

1 个答案:

答案 0 :(得分:-1)

不管采用这种将数据写入流中的方法的合理性,这里的问题都是存在一个地方,您只是“解雇”了异步任务。尤其是,如果您仔细查看_objectData.Select(async str => SafelyWrite(streamWriter, await str)),您会发现这里是枚举器,它在内部启动等待str任务的等待,但实际上并没有等待更高级别的这些过程的完成水平。所以代替

await Task.WhenAll(_objectData.Select(async str => SafelyWrite(streamWriter, await str)));

应该有

await Task.WhenAll((await Task.WhenAll(_objectData)).Select(str => SafelyWrite(streamWriter, str)));

为了增加可读性,并且为了避免对第二个选项的误解,此处的等效项是

var results = await Task.WhenAll(_objectData);
var writeTasks = results.Select(str => SafelyWrite(streamWriter, str));
await Task.WhenAll(writeTasks);