异步文件写入问题

4

我有一个测试方法,其中我正在测试异步文件写入

[TestMethod]
public async Task TestMethod1()
{
    List<Task> tasks = null;
    int x = 1;
    int step = 10;
    for (int i = step; i <=200; i = i + step)
    {
        tasks = Enumerable.Range(x, step).Select(async y =>
            {
                await TextFile.WriteTextAsync("file.txt", String.Format("{0}\n", y));
            }).ToList();

        x = i + 1;
        await Task.WhenAll(tasks);
    }
}   

异步文件写入代码:

public static async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.ReadWrite,
        bufferSize: 4096, useAsync: true))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    };
}

问题在于我的代码生成的文件没有包含所有预期值。
我期望在文件中看到从1到200的值,但实际上我看到了例如:
1 
3
5
7
8

12
13
14 
...

请在此处查看详细的文件:http://bit.ly/1JVMAyg

注意:请参见下面我的解决方案,可以修复未插入文件中的缺失项目的问题,但它破坏了@LasseV.Karlsen在他的评论中提到的多线程的整个想法。如果有更好的解决方案不会破坏多线程,请让我知道。


4
你有多个线程同时向同一个文件写入。这看起来不太可能会有好的结果。 - Jon Skeet
1个回答

0

感谢 @JonSkeet。我明白了。我必须限制对“WriteTextAsync”方法的访问,这是我的解决方案:

private static SemaphoreSlim _thread= new SemaphoreSlim(1);    
public static async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);
    await _sync.WaitAsync();
    try
    {

        using (FileStream sourceStream = new FileStream(filePath,
            FileMode.Append, FileAccess.Write, FileShare.ReadWrite,
            bufferSize: 4096, useAsync: true))
        {
            await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
        };
    }

    catch(Exception ex)
    {
        Debug.WriteLine(ex.ToString());
    }
    finally
    {
        _thread.Release();
    }
}

注意: 此解决方案修复了未插入文件的丢失项问题,但现在它将WriteTextAsync限制为一次只能有一个线程访问文件,正如@LasseV.Karlsen所提到的。

因此,看起来我的解决方案解决了问题,但破坏了多线程的整个思想,如果有更好的解决方案不会破坏多线程,我很乐意看到。


3
但如果每次只有一个线程写入文件,那么整个线程是为什么而存在的呢?这就好比让N个顾客进入商店,但商店只有一条结账队列,难道我理解错了吗? - Lasse V. Karlsen
@LasseVKarlsen 实际上我根本看不到任何线程...除非默认的调度程序是嗯.. 默认的调度程序... - Aron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接