您好,登錄后才能下訂單哦!
今天小編給大家分享一下C#的高效IO庫System.IO.Pipelines怎么使用的相關(guān)知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
可能不能在一次read操作中讀入所有需要的數(shù)據(jù),因此需要在緩沖區(qū)中維護一個游標,記錄下次讀取操作的起始位置,這個游標帶了了不小的復雜度:
從緩沖區(qū)讀數(shù)據(jù)時,要根據(jù)游標計算緩沖區(qū)起始寫位置,以及剩余空間大小。增加了讀數(shù)據(jù)的復雜度。
解析數(shù)據(jù)也是復用這個緩沖區(qū)的,解析的時候也要判斷游標起始位置,剩余空間大小。同時增加了解析數(shù)據(jù)的復雜度。
解析玩了后還要移動游標,重新標記緩沖區(qū)起始位置,再次增加了復雜度。
由于緩沖區(qū)有限,可能申請的緩沖區(qū)不夠用,需要引入動態(tài)緩沖區(qū)。這也大幅加大了代碼的復雜度。
如果每次都申請更大的內(nèi)存,一方面帶來的內(nèi)存申請釋放開銷,另一方面需要將原來的數(shù)據(jù)移動,并更新游標,帶來更復雜的邏輯。
如果靠多段的內(nèi)存組成一個邏輯整理,數(shù)據(jù)的讀寫方式都比較復雜。
使用完后的內(nèi)存要釋放,如果需要更高的效率還要維持一個內(nèi)存池。
我們的業(yè)務本身只關(guān)心使用操作,但讀和用操作沒有分離,復雜的都操作導致用操作也變得復雜,并且嚴重干擾業(yè)務邏輯。
今天介紹微軟新推出的一個庫:System.IO.Pipelines(需要在Nuget上安裝),用于解決這些痛點。它主要包含一個Pipe對象,它有一個Writer屬性和Reader屬性。
var pipe = new Pipe(); var writer = pipe.Writer; var reader = pipe.Reader;
Writer對象用于從數(shù)據(jù)源讀取數(shù)據(jù),將數(shù)據(jù)寫入管道中;它對應業(yè)務中的"讀"操作。
var content = Encoding.Default.GetBytes("hello world"); var data = new Memory<byte>(content); var result = await writer.WriteAsync(data);
另外,它也有一種使用Pipe申請Memory的方式
var buffer = writer.GetMemory(512); content.CopyTo(buffer); writer.Advance(content.Length); var result = await writer.FlushAsync();
Reader對象用于從管道中獲取數(shù)據(jù)源,它對應業(yè)務中的"用"操作。
首先獲取管道的緩沖區(qū):
var result = await reader.ReadAsync(); var buffer = result.Buffer;
這個Buffer是一個ReadOnlySequence<byte>對象,它是一個相當好的動態(tài)內(nèi)存對象,并且相當高效。它本身由多段Memory<byte>組成,查看Memory段的方法有:
IsSingleSegment: 判斷是否只有一段Memory<byte>
First: 獲取第一段Memory<byte>
GetEnumerator: 獲取分段的Memory<byte>
它從邏輯上也可以看成一段連續(xù)的Memory<byte>,也有類似的方法:
Length: 整個數(shù)據(jù)緩沖區(qū)長度
Slice: 分割緩沖區(qū)
CopyTo: 將內(nèi)容復制到Span中
ToArray: 將內(nèi)容復制到byte[]中
另外,它還有一個類似游標的位置對象SequencePosition,可以從其Position相關(guān)函數(shù)中使用,這里就不多介紹了。
這個緩沖區(qū)解決了"數(shù)據(jù)讀不夠"的問題,一次讀取的不夠下次可以接著讀,不用緩沖區(qū)的動態(tài)分配,高效的內(nèi)存管理方式帶來了良好的性能,好用的接口是我們能更關(guān)注業(yè)務。
獲取到緩沖區(qū)后,就是使用緩沖區(qū)的數(shù)據(jù)
var data = buffer.ToArray();
使用完后,告訴PIPE當前使用了多少數(shù)據(jù),下次接著從結(jié)束位置后讀起
reader.AdvanceTo(buffer.GetPosition(4));
這是一個相當實用的設計,它解決了"讀了就得用"的問題,不僅可以將不用的數(shù)據(jù)下次再使用,還可以實現(xiàn)Peek的操作,只讀但不改變游標。
除了"讀"和"用"操作外,它們之間還需要一些交互,例如:
讀過程中數(shù)據(jù)源不可用,需要停止使用
使用過程中業(yè)務結(jié)束,需要中止數(shù)據(jù)源。
Reader和Writer都有一個Complete函數(shù),用于通知結(jié)束:
reader.Complete(); writer.Complete();
在Writer寫入和Reader讀取時,會獲得一個結(jié)果
FlushResult result = await writer.FlushAsync(); ReadResult result = await reader.ReadAsync();
它們都有一個IsComplete屬性,可以根據(jù)它是否為true判斷是否已經(jīng)結(jié)束了讀和寫的操作。
在寫入和讀取的時候,也可以傳入一個CancellationToken,用于取消相應的操作。
writer.FlushAsync(CancellationToken.None); reader.ReadAsync(CancellationToken.None);
如果取消成功,對應的Result的IsCanceled則為true(沒有驗證過)
以上就是“C#的高效IO庫System.IO.Pipelines怎么使用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關(guān)注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。