繁体   English   中英

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

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

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

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

码:

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进行负载测试期间,会发生这种情况。

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

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

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

问题不在于:

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

注意事项:

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

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架构,该如何进行负载测试?

1. 线程安全ASP.NET

暂无
暂无

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

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