简体   繁体   English

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

[英]StreamWriter/Reader reading and then immediately writing causes exception

I need to read a number from a file and then increment the number and update the same file just for debugging purposes. 我需要从文件中读取一个数字,然后递增该数字并更新同一文件,仅用于调试目的。 I wrote this code and to my surprise it throws an exception (it is just for debugging but nonetheless I would like to get to the bottom of this): 我编写了这段代码,令我惊讶的是,它引发了一个异常(它仅用于调试,但是我还是想深入了解一下):

The process cannot access the file '' because it is being used by another process. 该进程无法访问文件”,因为它正在被另一个进程使用。

Code: 码:

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);
}

Then I wanted to narrow the issue down to either reading or writing, so I did this: 然后我想把问题缩小到阅读或写作上,所以我这样做了:

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...");
}

I am getting this so this tells me it happens during both but randomly: 我得到这个,所以这告诉我这是在两个过程中随机发生的:

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...

Just a note that this code is in the Controller of an MVC app within this method: 请注意,此代码在此方法中的MVC应用程序的Controller中:

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

I used Process Explorer and nothing else is using the file. 我使用了Process Explorer ,其他都没有使用该文件。

Question : I am disposing things here so why the exception? 问题 :我在这里放置东西,为什么要例外?

At first I thought perhaps there is a delay in disposing the reader but in that case all exceptions should be about reader but this is not the case. 起初,我认为也许在配置reader存在延迟,但是在这种情况下,所有例外都应与reader有关,但事实并非如此。 Also, below will also give the same exception: 另外,下面还将给出相同的例外:

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());

There are no threads. 没有线程。 Just HTTP GET (regular and via AJAX). 仅HTTP GET(常规和通过AJAX)。

EDIT 编辑

This happens during load testing using Visual Studio 2015. 在使用Visual Studio 2015进行负载测试期间,会发生这种情况。

I've run into this problem and I solved it by adding a while loop. 我遇到了这个问题,并通过添加while循环解决了这个问题。

Try doing this and see if it solves your problem. 尝试这样做,看看是否能解决您的问题。

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

The issue is NOT because of: 问题不在于:

  1. GC not deallocating and the code reaching writing before reader is collected. GC未取消分配,并且代码已在收集reader之前达到写入状态。 I tested the exact code with a console application and the issue cannot be replicated. 我使用控制台应用程序测试了确切的代码,并且该问题无法复制。
  2. This is not due to threading ( except for one caveat ) because I am not creating any threads. 这不是由于线程( 除了一个警告 ),因为我没有创建任何线程。 Within ASP.NET each request gets assigned a thread from the pool and an instance of the class with be created for each thread 1 . 在ASP.NET中,每个请求都会从池中分配一个线程,并为每个线程1创建一个类的实例。 If there are class level things ( static ), then they obviously will not be threadsafe. 如果有类级别的东西( static ),那么它们显然将不是线程安全的。 They will be shared. 他们将被共享。 But this code is not within a static context. 但是此代码不在静态上下文中。

Here is the caveat: 注意事项:

When using a browser, this issue was never replicated. 使用浏览器时,从未复制此问题。 I also did something simple like this: 我还做了一些简单的事情,像这样:

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);
}

Now with the above code, when the requests are made through a browser, as expected, the contents of the file are as shown below. 现在有了上面的代码,当按预期通过浏览器发出请求时,文件的内容如下所示。 Notice every entry is synchronous : 注意每个条目都是同步的

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
...

But during Visual Studio load testing, the contents are like this and the entry into the method is not synchronous : 但是在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
...

Conclusion 结论

In conclusion, when doing a load test with Visual Studio, the call behavior is not the exact same as it would be from a browser. 总之,使用Visual Studio进行负载测试时,调用行为与从浏览器中获得的调用行为并不完全相同。 For some reason, each thread is not given its own instance of the class. 由于某种原因,每个线程都没有获得其自己的类实例。 I have no idea why but if someone does, please chime in. I think this is bullcrap if you ask me: How can I do a load test if it is doing something which is totally against the ASP.NET architecture? 我不知道为什么,但是如果有人这样做,请发出提示。如果您问我,这就是废话: 如果它所做的工作完全违背ASP.NET架构,该如何进行负载测试?

1. Thread safety ASP.NET 1. 线程安全ASP.NET

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM