StreamWriter / Reader读取然后立即写入会导致异常

时间:2018-03-14 18:55:31

标签: c# asp.net-mvc io

我需要从文件中读取一个数字,然后递增数字并更新同一个文件,仅用于调试目的。我编写了这段代码,令我惊讶的是它引发了一个异常(它只是用于调试,但我仍然想要了解它):

  

该进程无法访问该文件,因为它正被另一个进程使用。

代码:

string path = Server.MapPath("~/Log.txt");

int newTotal = 0;

using (var reader = new StreamReader(path))
{
    var total = reader.ReadLine();

    if (total != null)
    {
        newTotal = int.Parse(total) + 1;
    }
}

using (var writer = new StreamWriter(path, false))
{
    // I added AutoFlush because I read somewhere on SO 
    // this will write to disk immediately
    writer.AutoFlush = true; 
    writer.Write(newTotal);
}

然后我想把问题缩小到阅读或写作,所以我这样做了:

string path = Server.MapPath("~/Log.txt");

int newTotal = 0;

try
{
    using (var reader = new StreamReader(path))
    {
        var total = reader.ReadLine();

        if (total != null)
        {
            newTotal = int.Parse(total) + 1;
        }
    }
}
catch (Exception)
{
    throw new System.Web.HttpException("During reading...");
}

try
{
    using (var writer = new StreamWriter(path, false))
    {
        writer.AutoFlush = true;
        writer.Write(newTotal);
    }
}
catch (Exception)
{
    throw new System.Web.HttpException("During writing...");
}

我得到了这个,所以这告诉我它发生在两个期间但随机发生:

During reading...
During writing...
During reading...
During writing...
During reading...
During reading...
During writing...
During writing...
During writing...
During writing...
During writing...
During reading...
During reading...
During reading...

请注意,此代码位于此方法中的MVC应用的Controller中:

protected override void Initialize(RequestContext requestContext)
{
    base.Initialize(requestContext);
    // Code is here
}

我使用 Process Explorer ,没有其他人正在使用该文件。

问题:我在这里处理的事情为什么例外?

起初我认为处理reader可能会有延迟,但在这种情况下,所有异常都应该是reader,但事实并非如此。另外,下面也会给出相同的例外:

this.path = Server.MapPath("~/Log.txt");

var total = System.IO.File.ReadAllText(this.path);
int newTotal = 0;

if (total != null)
{
    newTotal = int.Parse(total) + 1;
}

System.IO.File.WriteAllText(this.path, newTotal.ToString());

没有线程。只需HTTP GET(常规和通过AJAX)。

修改

在使用Visual Studio 2015进行负载测试期间会发生这种情况。

2 个答案:

答案 0 :(得分:0)

我遇到了这个问题,我通过添加while循环解决了这个问题。

尝试这样做,看看它是否能解决您的问题。

using (var reader = new StreamReader(path))
{
    while (reader.Peek() > -1) 
    {
        var total = reader.ReadLine();
        newTotal = int.Parse(total) + 1;
    }
}

答案 1 :(得分:0)

问题不在于:

  1. GC未解除分配,并且收集了在reader之前写入的代码。我使用控制台应用程序测试了确切的代码,但问题无法复制。
  2. 这不是因为线程(除了一个警告),因为我没有创建任何线程。在ASP.NET中,每个请求都从池中分配一个线程,并为每个线程 1 创建一个类的实例。如果有类级别的东西(static),那么它们显然不是线程安全的。他们将被分享。但是这段代码不在静态环境中。
  3. 以下是警告:

    使用浏览器时,从未复制此问题。我也做了这样简单的事情:

    protected override void Initialize(RequestContext requestContext)
    {
         System.IO.File.AppendAllText(tPath, "Thread enter and ID is: " + 
             System.Threading.Thread.CurrentThread.ManagedThreadId + Environment.NewLine);
         // Placed all code here
         System.IO.File.AppendAllText(tPath, "Thread exit and ID is: " + 
             System.Threading.Thread.CurrentThread.ManagedThreadId + Environment.NewLine);
    }
    

    现在使用上面的代码,当通过浏览器发出请求时,正如预期的那样,文件的内容如下所示。请注意,每个条目都是同步

    Thread enter and ID is: 35
    Thread exit and ID is: 35
    Thread enter and ID is: 11
    Thread exit and ID is: 11
    Thread enter and ID is: 29
    Thread exit and ID is: 29
    Thread enter and ID is: 36
    Thread exit and ID is: 36
    Thread enter and ID is: 27
    Thread exit and ID is: 27
    Thread enter and ID is: 11
    Thread exit and ID is: 11
    Thread enter and ID is: 29
    Thread exit and ID is: 29
    Thread enter and ID is: 8
    Thread exit and ID is: 8
    Thread enter and ID is: 11
    Thread exit and ID is: 11
    Thread enter and ID is: 36
    Thread exit and ID is: 36
    ...
    

    但是在Visual Studio负载测试期间,内容是这样的,并且方法的输入是不同步

    Thread enter and ID is: 12
    Thread exit and ID is: 12
    Thread enter and ID is: 29
    Thread enter and ID is: 49
    Thread enter and ID is: 51
    Thread exit and ID is: 29
    Thread exit and ID is: 51
    Thread enter and ID is: 48
    Thread exit and ID is: 48
    Thread enter and ID is: 57
    Thread exit and ID is: 57
    Thread enter and ID is: 17
    Thread exit and ID is: 17
    Thread enter and ID is: 55
    Thread exit and ID is: 55
    Thread enter and ID is: 42
    Thread exit and ID is: 42
    Thread enter and ID is: 47
    Thread enter and ID is: 55
    ...
    

    <强>结论

    总之,在使用Visual Studio进行负载测试时,调用行为与浏览器的调用行为不完全相同。由于某种原因,每个线程都没有给出自己的类实例。我不知道为什么,但如果有人这样做,请插入。如果你问我,我认为这是一个公牛:如果它做了一些完全违反ASP.NET架构的事情,我怎么能进行负载测试呢? / em>的

    <子> 1。 Thread safety ASP.NET