簡體   English   中英

檢查 StreamReader 是否有可用數據的非阻塞方式

[英]Non-blocking way to check if a StreamReader has data available

我有一個StreamReader ,我想知道是否有數據可用而不阻塞線程。

我嘗試了Peek方法,但是當沒有可用數據時它會阻塞。

using (StreamReader reader = new StreamReader(stream))
{
    if (reader.Peek() == -1) // Blocks here while there is no data and unblocks as soon as there is data.
    {

    }
}

如果我檢查Peek() 方法的單聲道代碼,它會在評論中說

    //
    // Peek can block:
    // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=96484
    //

不幸的是,該鏈接不再有效。

我在這里這里這里這里發現微軟似乎有一個導致Peek阻塞的錯誤。 但是所有這些帖子都很老了。 我認為由於這個錯誤,mono 故意讓Peek()阻塞。

所以我有兩個問題

  1. 微軟有一個導致Peek()阻塞的錯誤仍然是真的嗎? 如果不是,mono 應該將Peek()的實現更改為非阻塞。
  2. 有沒有其他方法可以在不阻塞線程的情況下檢查 StreamReader 是否有可用數據?

好的,我只想說我真的不知道你在這里想要完成什么。 但是,據我所知, Peek方法必須阻止當前線程才能工作。 這就是文檔所說的:

Peek 方法返回一個整數值以確定是文件結束還是發生了其他錯誤。 這允許用戶在將其轉換為 Char 類型之前首先檢查返回的值是否為 -1。

因此, Peek只應在遇到錯誤或文件結尾時返回 -1。 這有點令人困惑,因為可能不涉及文件。 流可能是來自WebRequest的響應,在這種情況下,您嘗試讀取的流部分可能尚未下載。 因此, Peek必須等到它完成,因為從文檔中並不清楚,它返回從流中讀取的第一個字節。

您發布的鏈接中提到的問題與使用相同StreamReader的多個線程有關,這不是您的情況。 我也相信曾經有一個錯誤會導致一個StreamReader等待輸入阻塞另一個,但我相信它已經被修復了。 我不確定 Mono 的實現是做什么的。

要回答您的問題,要在不阻塞線程的情況下執行此操作,我會嘗試以下操作:

  1. 只需將整個內容放入一個單獨的線程中即可。 然后你不會在乎它是否被阻止。
  2. 使用ReadAsync然后在任務上使用awaitContinueWith以使其非阻塞。

但是,正如評論中正確指出的那樣,如果您將整個內容放到另一個線程中,您真的需要Peek嗎? 為什么不將其放入典型的while (Read(...)) { ... }塊中並在數據到來時對其進行處理?

  1. 我不能給出任何答案,我沒有任何具體的案例可以重現和測試,顯然來源不可用。
  2. 使用 .NET 4.5,您可以使用 StreamReader 類中的 ReadAsync 方法

我試圖讀取子進程的重定向標准輸出並遇到了同樣的問題。 如果有,我想讀取所有字符,否則返回一個空字符串而不阻塞當前線程。

[第一次嘗試]
通常,我們可以通過檢查流的長度來實現這一點。 但是,就我而言, StreamReaderBaseStream不支持查找,這只會引發異常。

[第二次嘗試]
我轉向Peek方法。 不幸的是,正如這個問題中提到的,這是一個阻塞調用。

[最后的斗爭]
我為異步 I/O 方法實現了一個包裝器,並最終解決了這個問題(我希望如此)。

public static async void appendAll(this StringBuilder sb,
    StreamReader sr, int msTimeout, int bufSize = 4096) {
    for (char[] buf = new char[bufSize]; ;) {
        var n = sr.ReadAsync(buf, 0, buf.Length);
        if (!n.Wait(msTimeout)) { break; }
        sb.Append(new Span<char>(buf, 0, await n));
    }
}

一個可能的問題是,如果流在超時后被強制關閉,即其對應的進程被殺死,異步任務內部可能會拋出異常。 我不確定它是否會導致崩潰。
但是,如果我理解正確, AggregateException將引發Wait調用,如果我們不再在此任務上調用Wait ,它不會打擾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM