簡體   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