環形緩衝,java
本質就是隊列fifo,先進先出的特殊版本,環形隊列,是用空間獲得了順序存儲的快索引的優勢,又避免了刪除,移動數據的缺點。而且還享受了單生產/單消費,2線程的無鎖線程優點。十分完美。c++
1.面對頻率超級頻繁的讀寫,環形緩衝修改成固定大小的隊列,不添加操做,而且使用後,也不刪除和移動。壞處是,必須預設內存空間。因此適合超級頻繁的讀寫,反正基本是一直佔用。c#
2.由於要實現環形,因此通常有2個哨兵,若是是2個線程,一個讀一個寫。環形緩衝,還能夠避免線程鎖。很是棒。即所謂單生產/單消費模式的共享隊列是不須要加鎖同步的數組
3.固定大小。因此數組 xxx[],很是適合改造爲環形緩衝。char[] 改成字符羣緩衝 . object[] 改成對象羣緩衝緩存
花了點時間,寫了下。測試用例測試了下。沒發現問題。服務器
感受緩存區必須根據實際狀況寫特例。多線程
這裏緩存區,適合 讀必須大於寫。app
特色dom
1.寫滿會 自動跳過。 因此須要根據狀況,定製緩存區大小,或者改寫爲自動擴大緩存區。性能
2.讀,若是無數據會直接出去,無阻塞.
3. 若是可行的話,可使用多個ringbuff,來代替多線程的方案
需改進:
定義一個最大緩存區大小。讓緩存區能夠自動擴大,到最大就不擴大了。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BaseLib { /// <summary> /// 環形緩衝區. c# byte== c++ unsign char . c# char==c ++ char. /// 環形緩衝結構,不考慮在讀或寫某端有多線程的狀況,由於環形緩衝結構就是爲了避免鎖下的性能,適合讀寫同一個線程,或者讀寫各一個線程。 /// </summary> public class RingBuff { private byte[] ringBuff; private int nextWritePos; private int nextReadPos; private int buffSize; private int capcity; public RingBuff(int _size) { capcity=buffSize = _size; ringBuff = new byte[buffSize]; nextWritePos = 0; nextReadPos = 0; } /// <summary> /// 寫入緩存 /// </summary> /// <param name="_buff">要寫入的數據</param> /// <returns>是否寫入</returns> public bool WriteBuff(byte[] _buff) { bool ret = false; int bsize = _buff.Length; if (capcity < bsize) { ret = false; } else { int rightLeft = buffSize - nextWritePos; //need reture to head if (bsize > rightLeft) { Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft); Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft); nextWritePos = bsize - rightLeft; } else if (bsize == rightLeft) { Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); nextWritePos = 0; } else { Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); nextWritePos += bsize; } capcity = capcity - bsize; ret = true; } return ret; } /// <summary> /// 寫入緩存,指定讀取源的長度. /// </summary> /// <param name="_buff"></param> /// <param name="len"></param> /// <returns></returns> public bool WriteBuff(byte[] _buff, int len) { int bsize = len;// _buff.Length; bsize = len > _buff.Length ? _buff.Length : bsize; if (capcity < bsize) { return false; } else { int rightLeft = buffSize - nextWritePos; //need reture to head if (bsize > rightLeft) { Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft); Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft); nextWritePos = bsize - rightLeft; } else if (bsize == rightLeft) { Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); nextWritePos = 0; } else { Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); nextWritePos += bsize; } capcity -= bsize; return true; } } /// <summary> /// 讀緩存,是否預讀,而不移動讀哨兵. /// </summary> /// <param name="readbuff">讀入的臨時緩存</param> /// <returns>實際讀出的數據長度</returns> public int ReadBuff(ref byte[] readbuff, bool MovePosition = true) { int len = readbuff.Length; int enableread = buffSize - capcity; Array.Clear(readbuff, 0, len); if (len <= 0 || enableread <= 0) { return 0; } else { int realRead = enableread >= len ? len : enableread; int rightLeft = buffSize - nextReadPos; if (realRead > rightLeft) { Array.Copy(ringBuff, nextReadPos, readbuff, 0, rightLeft); Array.Copy(ringBuff, 0, readbuff, rightLeft, realRead - rightLeft); if (MovePosition) { nextReadPos = realRead - rightLeft; } } else if (realRead == rightLeft) { Array.Copy(ringBuff, nextReadPos, readbuff, 0, realRead); if (MovePosition) { nextReadPos = 0; } } else { Array.Copy(ringBuff, nextReadPos, readbuff, 0, realRead); if (MovePosition) { nextReadPos += realRead; } } capcity += realRead; return realRead; } } public string GetBuffInfo() { StringBuilder sb = new StringBuilder(); sb.Append(System.Threading.Thread.CurrentThread.Name + ":writePositon:" + nextWritePos.ToString()); sb.Append(". readPosition:" + nextReadPos.ToString()); sb.Append(". size:"); sb.Append(buffSize); sb.Append(" .enable read:" + (buffSize-capcity).ToString() + ".enable write:" + capcity.ToString()); sb.Append(System.Environment.NewLine); sb.Append("1-10 byte: "); for (int i = 0; i < 10; i++) { sb.Append(ringBuff[i].ToString("x")+"|"); } return sb.ToString(); } private RingBuff() { } } }
測試例子
static void TestRingBuff() { int buffSize = 10; BaseLib.RingBuff rb = new BaseLib.RingBuff(buffSize); Console.WriteLine(rb.GetBuffInfo()); ////測試讀滿,和寫滿。 //for (int i = 0; i < 12; i++) //{ // rb.WriteBuff(new byte[] { (byte)testChar }); // testChar++; // Console.WriteLine(rb.GetBuffInfo()); //} //byte[] tempReadBuff = new byte[1]; //for (int i = 0; i < 15; i++) //{ // rb.ReadBuff(ref tempReadBuff); // Console.WriteLine(tempReadBuff[0].ToString("x")); // Console.WriteLine(rb.GetBuffInfo()); //} //////字符是依次 + 1寫入緩存。因此測試首先關注各類狀況下,是否讀出的數據是聯繫的。就可大概肯定數據是沒有丟失和跳躍的。 ////測試讀慢,寫快. //while (true) //{ // bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar, (byte)++testChar }); // if (ret == false) // { // --testChar; // --testChar; // --testChar; // } // Console.WriteLine(rb.GetBuffInfo()); // byte[] tempReadBuff = new byte[2]; // rb.ReadBuff(ref tempReadBuff); // Console.WriteLine(tempReadBuff[0].ToString("x") + "." + tempReadBuff[1].ToString("x")); // ++testChar; // System.Threading.Thread.Sleep(1000); //} ////測試讀快,慢寫 //while (true) //{ // bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar }); // if (ret == false) // { // --testChar; // --testChar; // } // Console.WriteLine(rb.GetBuffInfo()); // byte[] tempReadBuff = new byte[3]; // rb.ReadBuff(ref tempReadBuff); // Console.WriteLine(tempReadBuff[0].ToString() + "." + tempReadBuff[1].ToString() + "." + tempReadBuff[2].ToString()); // Console.WriteLine(rb.GetBuffInfo()); // ++testChar; // System.Threading.Thread.Sleep(1000); //} //////隨機測試。 //while (true) //{ // bool ret = rb.WriteBuff(new byte[] { (byte)testChar, (byte)++testChar, (byte)++testChar }); // if (ret == false) // { // --testChar; // --testChar; // --testChar; // } // Console.WriteLine(rb.GetBuffInfo()); // Random rd = new Random(); // int rint = (rd.Next() + 2) % 10; // byte[] tempReadBuff = new byte[rint]; // Console.Write("read " + rint.ToString("x") + " :"); // rb.ReadBuff(ref tempReadBuff); // for (int i = 0; i < rint; ++i) // { // Console.Write(tempReadBuff[i].ToString("x") + " "); // } // Console.Write("\r\n"); // Console.WriteLine(rb.GetBuffInfo()); // ++testChar; // System.Threading.Thread.Sleep(1000); //} Console.Read(); }
java 版本
明顯發現java和c#基本語法就像雙胞胎。爲何好多人包括以前的本身,會排斥另外一種語言呢?
特定:讀完,寫滿,以後都不工做了。
unusedSize;//冗餘這個字段既能夠提升效率,也能夠區分空仍是滿的狀況(單靠2個指針區分不了)。
package com.datastructurn; public class RingBuff { private byte[] ringBuff; private Integer nextWritePosition; private Integer nextReadPosition; private Integer buffSize; private Integer unusedSize;//冗餘這個字段既能夠提升效率,也能夠區分空仍是滿的狀況(單靠2個指針區分不了)。 public RingBuff(int _size) { buffSize= unusedSize=_size; ringBuff=new byte[buffSize]; nextReadPosition=nextWritePosition=0; } public boolean WriteBuff(byte[] _buff) { boolean ret = false; int bsize = _buff.length; if (unusedSize < bsize) { ret = false; } else { int rightLeft = buffSize - nextWritePosition; //need reture to head if (bsize > rightLeft) { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, rightLeft); System.arraycopy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft); nextWritePosition = bsize - rightLeft; } else if (bsize == rightLeft) { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize); nextWritePosition = 0; } else { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize); nextWritePosition += bsize; } unusedSize = unusedSize - bsize; ret = true; } return ret; } public boolean WriteBuff(byte[] _buff, int len) { int bsize = len;// _buff.Length; bsize = len > _buff.length ? _buff.length : bsize; if (unusedSize < bsize) { return false; } else { int rightLeft = buffSize - nextWritePosition; //need reture to head if (bsize > rightLeft) { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, rightLeft); System.arraycopy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft); nextWritePosition = bsize - rightLeft; } else if (bsize == rightLeft) { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize); nextWritePosition = 0; } else { System.arraycopy(_buff, 0, ringBuff, nextWritePosition, bsize); nextWritePosition += bsize; } unusedSize -= bsize; return true; } } /// <summary> /// 讀緩存,是否預讀,而不移動讀哨兵. /// </summary> /// <param name="readbuff">讀入的臨時緩存</param> /// <returns>實際讀出的數據長度</returns> public int ReadBuff(byte[] readbuff, Boolean MovePosition ) { if(MovePosition==null) { MovePosition=true; } int len = readbuff.length; int enableread = buffSize - unusedSize; //Array.Clear(readbuff, 0, len); if (len <= 0 || enableread <= 0) { return 0; } else { int realRead = enableread >= len ? len : enableread; int rightLeft = buffSize - nextReadPosition; if (realRead > rightLeft) { System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, rightLeft); System.arraycopy(ringBuff, 0, readbuff, rightLeft, realRead - rightLeft); if (MovePosition) { nextReadPosition = realRead - rightLeft; } } else if (realRead == rightLeft) { System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, realRead); if (MovePosition) { nextReadPosition = 0; } } else { System.arraycopy(ringBuff, nextReadPosition, readbuff, 0, realRead); if (MovePosition) { nextReadPosition += realRead; } } unusedSize += realRead; return realRead; } } public String GetBuffInfo() { StringBuilder sb = new StringBuilder(); sb.append(":writePositon:" + nextWritePosition); sb.append(". readPosition:" + nextReadPosition); sb.append(". size:"); sb.append(buffSize); sb.append(" .enable read:" + (buffSize-unusedSize) + ".enable write:" + unusedSize); sb.append("\r\n"); sb.append("1-10 byte: "); for (int i = 0; i < 10; i++) { sb.append(ringBuff[i]); } return sb.toString(); } }
共享內存
using System; using System.Collections.Generic; using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace control { public class ShareMemory { [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); //int+int+10*10=108int size = Marshal.SizeOf(typeof(char)); public void CreateShareFile(int size) { using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\aa.data", FileMode.Open, "test", size+12)) { //經過指定的 偏移量和大小 建立內存映射文件視圖服務器 using (var accessor = mmf.CreateViewAccessor()) //偏移量,能夠控制數據存儲的內存位置;大小,用來控制存儲所佔用的空間 { accessor.Write(0, 16);//nextWritePos accessor.Write(4, 16);//nextReadPos; accessor.Write(8, size);//buffSize accessor.Write(12, size);//capcity } } } public int GetNextWritePos(MemoryMappedViewAccessor mmv) { return mmv.ReadInt32(0); } public void SetNextWritePos(MemoryMappedViewAccessor mmv,int value) { mmv.Write(0, value); } public int GetnextReadPos(MemoryMappedViewAccessor mmv) { return mmv.ReadInt32(4); } public void SetnextReadPos(MemoryMappedViewAccessor mmv, int value) { mmv.Write(4, value); } public int GetbuffSize(MemoryMappedViewAccessor mmv) { return mmv.ReadInt32(8); } public int Getcapcity(MemoryMappedViewAccessor mmv) { return mmv.ReadInt32(12); } public void Setcapcity(MemoryMappedViewAccessor mmv, int value) { mmv.Write(12, value); } public IntPtr changepd(byte[] write) { IntPtr write_data = Marshal.AllocHGlobal(write.Length); Marshal.Copy(write, 0, write_data, write.Length); Marshal.FreeHGlobal(write_data ); return write_data; } public bool Write(byte[] _buff) { bool ret = false; using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\aa.data", FileMode.Open, "test", 108)) { using (var accessor = mmf.CreateViewAccessor()) { int bsize = _buff.Length; if (Getcapcity(accessor) < bsize) { ret = false; } else { int rightLeft = GetbuffSize(accessor) - GetnextReadPos(accessor); if (bsize > rightLeft) { unsafe { byte* pb = (byte*)IntPtr.Zero; accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pb); CopyMemory((IntPtr)(pb), changepd(_buff), (uint)_buff.Length); } //Array.Copy(_buff, 0, ringBuff, nextWritePos, rightLeft); //Array.Copy(_buff, rightLeft, ringBuff, 0, bsize - rightLeft); SetNextWritePos(accessor, bsize - rightLeft); } else if (bsize == rightLeft) { //Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); SetNextWritePos(accessor, 16); } else { //Array.Copy(_buff, 0, ringBuff, nextWritePos, bsize); SetNextWritePos(accessor,GetnextReadPos(accessor)+bsize); } Setcapcity(accessor, Getcapcity(accessor) - bsize); ret = true; } } } return ret; } } }