C#對象二進位序列化優化:位域技術實現極限壓縮

来源:https://www.cnblogs.com/Dotnet9-com/p/17981055
-Advertisement-
Play Games

目錄1. 引言2. 優化過程2.1. 進程對象定義與初步分析2.2. 排除Json序列化2.3. 使用BinaryWriter進行二進位序列化2.4. 數據類型調整2.5. 再次數據類型調整與位域優化3. 優化效果與總結 1. 引言 在操作系統中,進程信息對於系統監控和性能分析至關重要。假設我們需要 ...


目錄

1. 引言

在操作系統中,進程信息對於系統監控和性能分析至關重要。假設我們需要開發一個監控程式,該程式能夠捕獲當前操作系統的進程信息,並將其高效地傳輸到其他端(如服務端或監控端)。在這個過程中,如何將捕獲到的進程對象轉換為二進位數據,併進行優化,以減小數據包的大小,成為了一個關鍵問題。本文將通過逐步分析,探討如何使用位域技術對C#對象進行二進位序列化優化。

操作系統進程信息

首先,我們給出了一個進程對象的欄位定義示例。為了通過網路(TCP/UDP)傳輸該對象,我們需要將其轉換為二進位格式。在這個過程中,如何做到最小的數據包大小是一個挑戰。

欄位名 說明 示例
PID 進程ID 10565
Name 進程名稱 碼界工坊
Publisher 發佈者 沙漠盡頭的狼
CommandLine 命令行 dotnet CodeWF.Tools.dll
CPU CPU(所有內核的總處理利用率) 2.3%
Memory 記憶體(進程占用的物理記憶體) 0.1%
Disk 磁碟(所有物理驅動器的總利用率) 0.1 MB/秒
Network 網路(當前主要網路上的網路利用率 0 Mbps
GPU GPU(所有GPU引擎的最高利用率) 2.2%
GPUEngine GPU引擎 GPU 0 - 3D
PowerUsage 電源使用情況(CPU、磁碟和GPU對功耗的影響)
PowerUsageTrend 電源使用情況趨勢(一段時間內CPU、磁碟和GPU對功耗的影響) 非常低
Type 進程類型 應用
Status 進程狀態 效率模式

2. 優化過程

2.1. 進程對象定義與初步分析

我們根據欄位的示例值確定了每個欄位的數據類型。

欄位名 數據類型 說明 示例
PID int 進程ID 10565
Name string? 進程名稱 碼界工坊
Publisher string? 發佈者 沙漠盡頭的狼
CommandLine string? 命令行 dotnet CodeWF.Tools.dll
CPU string? CPU(所有內核的總處理利用率) 2.3%
Memory string? 記憶體(進程占用的物理記憶體) 0.1%
Disk string? 磁碟(所有物理驅動器的總利用率) 0.1 MB/秒
Network string? 網路(當前主要網路上的網路利用率 0 Mbps
GPU string? GPU(所有GPU引擎的最高利用率) 2.2%
GPUEngine string? GPU引擎 GPU 0 - 3D
PowerUsage string? 電源使用情況(CPU、磁碟和GPU對功耗的影響)
PowerUsageTrend string? 電源使用情況趨勢(一段時間內CPU、磁碟和GPU對功耗的影響) 非常低
Type string? 進程類型 應用
Status string? 進程狀態 效率模式

創建一個C#類SystemProcess表示進程信息:

public class SystemProcess
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    public string? CPU { get; set; }
    public string? Memory { get; set; }
    public string? Disk { get; set; }
    public string? Network { get; set; }
    public string? GPU { get; set; }
    public string? GPUEngine { get; set; }
    public string? PowerUsage { get; set; }
    public string? PowerUsageTrend { get; set; }
    public string? Type { get; set; }
    public string? Status { get; set; }
}

定義測試數據

private SystemProcess _codeWFObject = new SystemProcess()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    CPU = "2.3%",
    Memory = "0.1%",
    Disk = "0.1 MB/秒",
    Network = "0 Mbps",
    GPU = "2.2%",
    GPUEngine = "GPU 0 - 3D",
    PowerUsage = "低",
    PowerUsageTrend = "非常低",
    Type = "應用",
    Status = "效率模式"
};

2.2. 排除Json序列化

將對象轉為Json欄位串,這在Web開發是最常見的,因為簡潔,前後端都方便處理:

public class SysteProcessUnitTest
{
    private readonly ITestOutputHelper _testOutputHelper;

    private SystemProcess _codeWFObject // 前面已給出定義,這裡省

    public SysteProcessUnitTest(ITestOutputHelper testOutputHelper)
    {
        _testOutputHelper = testOutputHelper;
    }

    /// <summary>
    /// Json序列化大小測試
    /// </summary>
    [Fact]
    public void Test_SerializeJsonData_Success()
    {
        var jsonData = JsonSerializer.Serialize(_codeWFObject);
        _testOutputHelper.WriteLine($"Json長度:{jsonData.Length}");

        var jsonDataBytes = Encoding.UTF8.GetBytes(jsonData);
        _testOutputHelper.WriteLine($"json二進位長度:{jsonDataBytes.Length}");
    }
}
標準輸出: 
Json長度:366
json二進位長度:366

儘管Json序列化在Web開發中非常流行,因為它簡潔且易於處理,但在TCP/UDP網路傳輸中,Json序列化可能導致不必要的數據包大小增加。因此,我們排除了Json序列化,並尋找其他更高效的二進位序列化方法。

{"PID":10565,"Name":"\u7801\u754C\u5DE5\u574A","Publisher":"\u6C99\u6F20\u5C3D\u5934\u7684\u72FC","CommandLine":"dotnet CodeWF.Tools.dll","CPU":"2.3%","Memory":"0.1%","Disk":"0.1 MB/\u79D2","Network":"0 Mbps","GPU":"2.2%","GPUEngine":"GPU 0 - 3D","PowerUsage":"\u4F4E","PowerUsageTrend":"\u975E\u5E38\u4F4E","Type":"\u5E94\u7528","Status":"\u6548\u7387\u6A21\u5F0F"}

2.3. 使用BinaryWriter進行二進位序列化

使用站長前面一篇文章寫的二進位序列化幫助類SerializeHelper轉換,該類使用BinaryWriter將對象轉換為二進位數據。

首先,我們使SystemProcess類實現了一個空介面INetObject,併在類上添加了NetHeadAttribute特性。

/// <summary>
/// 網路對象序列化介面
/// </summary>
public interface INetObject
{
}
[NetHead(1, 1)]
public class SystemProcess : INetObject
{
 	// 省略欄位定義   
}

然後,我們編寫了一個測試方法來驗證序列化和反序列化的正確性,並列印了序列化後的二進位數據長度。

/// <summary>
/// 二進位序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject, 1);
    _testOutputHelper.WriteLine($"序列化後二進位長度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
}
標準輸出: 
序列化後二進位長度:152

比Json體積小了一半多(366到152),上面單元測試也測試了數據反序列化後驗證數據是否正確,我們就以這個基礎繼續優化。

2.4. 數據類型調整

為了進一步優化二進位數據的大小,我們對數據類型進行了調整。通過對進程數據示例的分析,我們發現一些欄位的數據類型可以更加緊湊地表示。例如,CPU利用率可以只傳遞數字部分(如2.3),而不需要傳遞百分號。這種調整可以減小數據包的大小。

欄位名 數據類型 說明 示例
PID int 進程ID 10565
Name string? 進程名稱 碼界工坊
Publisher string? 發佈者 沙漠盡頭的狼
CommandLine string? 命令行 dotnet CodeWF.Tools.dll
CPU float CPU(所有內核的總處理利用率) 2.3
Memory float 記憶體(進程占用的物理記憶體) 0.1
Disk float 磁碟(所有物理驅動器的總利用率) 0.1
Network float 網路(當前主要網路上的網路利用率 0
GPU float GPU(所有GPU引擎的最高利用率) 2.2
GPUEngine byte GPU引擎,0:無,1:GPU 0 - 3D 1
PowerUsage byte 電源使用情況(CPU、磁碟和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 1
PowerUsageTrend byte 電源使用情況趨勢(一段時間內CPU、磁碟和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 0
Type byte 進程類型,0:應用,1:後臺進程 0
Status byte 進程狀態,0:正常運行,1:效率模式,2:掛起 1

修改測試數據定義:

[NetHead(1, 2)]
public class SystemProcess2 : INetObject
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    public float CPU { get; set; }
    public float Memory { get; set; }
    public float Disk { get; set; }
    public float Network { get; set; }
    public float GPU { get; set; }
    public byte GPUEngine { get; set; }
    public byte PowerUsage { get; set; }
    public byte PowerUsageTrend { get; set; }
    public byte Type { get; set; }
    public byte Status { get; set; }
}
/// <summary>
/// 普通優化欄位數據類型
/// </summary>
private SystemProcess2 _codeWFObject2 = new SystemProcess2()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    CPU = 2.3f,
    Memory = 0.1f,
    Disk = 0.1f,
    Network = 0,
    GPU = 2.2f,
    GPUEngine = 1,
    PowerUsage = 1,
    PowerUsageTrend = 0,
    Type = 0,
    Status = 1
};

添加單元測試如下:

/// <summary>
/// 二進位序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes2_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject2, 1);
    _testOutputHelper.WriteLine($"序列化後二進位長度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess2>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
    Assert.Equal(2.2f, deserializeObj.GPU);
}

測試結果:

標準輸出: 
序列化後二進位長度:99

又優化了50%左右(152到99),爽不爽?繼續,還有更爽的。

2.5. 再次數據類型調整與位域優化

更進一步地,我們引入了位域技術。位域允許我們更加精細地控制欄位在記憶體中的佈局,從而進一步減小二進位數據的大小。我們重新定義了欄位規則,並使用位域來表示一些枚舉值欄位。通過這種方式,我們能夠顯著地減小數據包的大小。

看前面一張表,部分欄位只是一些枚舉值,使用的byte表示,即8位(bit),其中比如進程類型只有2個狀態(0:應用,1:後臺進程),正好可以用1位即表示;像電源使用情況,無非就是5個狀態,用3位可表示全,按這個規則我們重新定義欄位規則如下:

欄位名 數據類型 說明 示例
PID int 進程ID 10565
Name string? 進程名稱 碼界工坊
Publisher string? 發佈者 沙漠盡頭的狼
CommandLine string? 命令行 dotnet CodeWF.Tools.dll
Data byte[8] 固定大小的幾個欄位,見下表定義

固定欄位(Data)的詳細說明如下:

欄位名 Offset Size 說明 示例
CPU 0 10 CPU(所有內核的總處理利用率),最後一位表示小數位,比如23表示2.3% 23
Memory 10 10 記憶體(進程占用的物理記憶體),最後一位表示小數位,比如1表示0.1%,值可根據基本信息計算 1
Disk 20 10 磁碟(所有物理驅動器的總利用率),最後一位表示小數位,比如1表示0.1%,值可根據基本信息計算 1
Network 30 10 網路(當前主要網路上的網路利用率),最後一位表示小數位,比如253表示25.3%,值可根據基本信息計算 0
GPU 40 10 GPU(所有GPU引擎的最高利用率),最後一位表示小數位,比如253表示25.3 22
GPUEngine 50 1 GPU引擎,0:無,1:GPU 0 - 3D 1
PowerUsage 51 3 電源使用情況(CPU、磁碟和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 1
PowerUsageTrend 54 3 電源使用情況趨勢(一段時間內CPU、磁碟和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 0
Type 57 1 進程類型,0:應用,1:後臺進程 0
Status 58 2 進程狀態,0:正常運行,1:效率模式,2:掛起 1

上面這張表是位域規則表,Offset表示欄位在Data位元組數組中的位置(以bit為單位計算),Size表示欄位在Data中占有的大小(同樣以bit單位計算),如Memory欄位,在Data位元組數組中,占據10到20位的空間。

修改類定義如下,註意看代碼中的註釋:

[NetHead(1, 3)]
public class SystemProcess3 : INetObject
{
    public int PID { get; set; }
    public string? Name { get; set; }
    public string? Publisher { get; set; }
    public string? CommandLine { get; set; }
    private byte[]? _data;
    /// <summary>
    /// 序列化,這是實際需要序列化的數據
    /// </summary>
    public byte[]? Data
    {
        get => _data;
        set
        {
            _data = value;

            // 這是關鍵:在反序列化將byte轉換為對象,方便程式中使用
            _processData = _data?.ToFieldObject<SystemProcessData>();
        }
    }

    private SystemProcessData? _processData;

    /// <summary>
    /// 進程數據,添加NetIgnoreMember在序列化會忽略
    /// </summary>
    [NetIgnoreMember]
    public SystemProcessData? ProcessData
    {
        get => _processData;
        set
        {
            _processData = value;

            // 這裡關鍵:將對象轉換為位域
            _data = _processData?.FieldObjectBuffer();
        }
    }
}

public record SystemProcessData
{
    [NetFieldOffset(0, 10)] public short CPU { get; set; }
    [NetFieldOffset(10, 10)] public short Memory { get; set; }
    [NetFieldOffset(20, 10)] public short Disk { get; set; }
    [NetFieldOffset(30, 10)] public short Network { get; set; }
    [NetFieldOffset(40, 10)] public short GPU { get; set; }
    [NetFieldOffset(50, 1)] public byte GPUEngine { get; set; }
    [NetFieldOffset(51, 3)] public byte PowerUsage { get; set; }
    [NetFieldOffset(54, 3)] public byte PowerUsageTrend { get; set; }
    [NetFieldOffset(57, 1)] public byte Type { get; set; }
    [NetFieldOffset(58, 2)] public byte Status { get; set; }
}

添加單元測試如下:

/// <summary>
/// 極限優化欄位數據類型
/// </summary>
private SystemProcess3 _codeWFObject3 = new SystemProcess3()
{
    PID = 10565,
    Name = "碼界工坊",
    Publisher = "沙漠盡頭的狼",
    CommandLine = "dotnet CodeWF.Tools.dll",
    ProcessData = new SystemProcessData()
    {
        CPU = 23,
        Memory = 1,
        Disk = 1,
        Network = 0,
        GPU = 22,
        GPUEngine = 1,
        PowerUsage = 1,
        PowerUsageTrend = 0,
        Type = 0,
        Status = 1
    }
};

/// <summary>
/// 二進位極限序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes3_Success()
{
    var buffer = SerializeHelper.SerializeByNative(_codeWFObject3, 1);
    _testOutputHelper.WriteLine($"序列化後二進位長度:{buffer.Length}");

    var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess3>(buffer);
    Assert.Equal("碼界工坊", deserializeObj.Name);
    Assert.Equal(23, deserializeObj.ProcessData.CPU);
    Assert.Equal(1, deserializeObj.ProcessData.PowerUsage);
}

測試輸出:

標準輸出: 
序列化後二進位長度:86

99又優化到86個位元組,13個位元組哦,有極限網路環境下非常可觀,比如100萬數據,那不就是12.4MB了?關於位域序列化和反序列的代碼這裡不細說了,很枯燥,站長可能也說不清楚,代碼長這樣:

public partial class SerializeHelper
{
    public static byte[] FieldObjectBuffer<T>(this T obj) where T : class
    {
        var properties = typeof(T).GetProperties();
        var totalSize = 0;

        // 計算總的bit長度
        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            totalSize = Math.Max(totalSize, offsetAttribute.Offset + offsetAttribute.Size);
        }

        var bufferLength = (int)Math.Ceiling((double)totalSize / 8);
        var buffer = new byte[bufferLength];

        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            dynamic value = property.GetValue(obj)!; // 使用dynamic類型動態獲取屬性值
            SetBitValue(ref buffer, value, offsetAttribute.Offset, offsetAttribute.Size);
        }

        return buffer;
    }

    public static T ToFieldObject<T>(this byte[] buffer) where T : class, new()
    {
        var obj = new T();
        var properties = typeof(T).GetProperties();

        foreach (var property in properties)
        {
            if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
            {
                continue;
            }

            var offsetAttribute =
                (NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
            dynamic value = GetValueFromBit(buffer, offsetAttribute.Offset, offsetAttribute.Size,
                property.PropertyType);
            property.SetValue(obj, value);
        }

        return obj;
    }

    /// <summary>
    /// 將值按位寫入buffer
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="value"></param>
    /// <param name="offset"></param>
    /// <param name="size"></param>
    private static void SetBitValue(ref byte[] buffer, int value, int offset, int size)
    {
        var mask = (1 << size) - 1;
        buffer[offset / 8] |= (byte)((value & mask) << (offset % 8));
        if (offset % 8 + size > 8)
        {
            buffer[offset / 8 + 1] |= (byte)((value & mask) >> (8 - offset % 8));
        }
    }

    /// <summary>
    /// 從buffer中按位讀取值
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="offset"></param>
    /// <param name="size"></param>
    /// <param name="propertyType"></param>
    /// <returns></returns>
    private static dynamic GetValueFromBit(byte[] buffer, int offset, int size, Type propertyType)
    {
        var mask = (1 << size) - 1;
        var bitValue = (buffer[offset / 8] >> (offset % 8)) & mask;
        if (offset % 8 + size > 8)
        {
            bitValue |= (buffer[offset / 8 + 1] << (8 - offset % 8)) & mask;
        }

        dynamic result = Convert.ChangeType(bitValue, propertyType); // 根據屬性類型進行轉換
        return result;
    }
}

3. 優化效果與總結

通過逐步優化,我們從最初的Json序列化366位元組減小到了使用普通二進位序列化的152位元組,再進一步使用位域技術優化到了86位元組。這種優化在網路傳輸中是非常可觀的,尤其是在需要傳輸大量數據的情況下。

本文通過一個示例案例,探討了C#對象二進位序列化的優化方法。通過使用位域技術,我們實現了對數據包大小的極限壓縮,提高了網路傳輸的效率。這對於開發C/S程式來說是一種樂趣,也是追求極致性能的一種體現。

最後,我們提供了本文測試源碼的Github鏈接,供讀者參考和學習。

彩蛋:該倉庫有上篇《C#百萬對象序列化深度剖析:如何在網路傳輸中實現速度與體積的完美平衡 (dotnet9.com)》案例代碼,也附帶了TCP、UDP服務端與客戶端聯調測試程式哦。

時間如流水,只能流去不流回。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、定義 定義一個操作中演算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類不改變一個演算法的結構即可重定義該演算法的特定步驟。模板方法是一種類行為型模式 二、描述 模板方法模式結構比較簡單,其核心是抽象類和其中的模板方法的設計,包含以下兩個角色: 1、AbstractClass(抽象類):在抽象 ...
  • 本文在原文基礎上有刪減,原文參考泛型、Trait 和生命周期。 目錄泛型數據類型在函數定義中使用泛型結構體定義中的泛型枚舉定義中的泛型方法定義中的泛型泛型代碼的性能Trait:定義共同行為定義 trait為類型實現 trait預設實現trait 作為參數Trait Bound 語法通過 + 指定多個 ...
  • 一、pom.xml需要引入的依賴二、項目開啟熔斷器開關 2.1 註解方式 2.2 xml方式三、依賴類缺失問題四、版本匹配安全檢查問題五、測試驗證六、結論 一、pom.xml需要引入的依賴 pom.xml <!-- springboot升級到2.6.7,同樣適用於2.7.0,2.7.18等 --> ...
  • 看到標題大家可能會有點疑惑吧:OpenFeign 不是挺好用的嗎?尤其是微服務之間的遠程調用,平時用的也挺習慣的,為啥要替換呢? ...
  • 當然,我寫的簡易版協程池還有很多可以優化的地方,比如可以實現動態擴容等功能。今天我們要簡單總結一下協程池的優勢,主要是為了降低資源開銷。協程池的好處在於可以重覆利用協程,避免頻繁創建和銷毀協程,從而減少系統開銷,提高系統性能。此外,協程池還可以提高響應速度,因為一旦接收到任務,可以立即執行,不需要等... ...
  • ZooKeeperServer 實現了單機版zookeeper服務端功能,子類實現了更加豐富的分散式集群功能: ZooKeeperServer |-- QuorumZooKeeperServer |-- LeaderZooKeeperServer |-- LearnerZooKeeperServer ...
  • 臨時接到一個需求說讓根據按照下麵的這個圖片的結構來打包下載指定位置下的文件到指定位置! 實現思路: 1.把已經實現的樹形結構的代碼進行調用,拿到他的數據進行創建對應的文件夾 2.因為結構下方的文件沒有特別直觀的資料庫中的關聯關係,所以還需要對於管理關係進行梳理 3.創建好階級文件,然後調用網上找的工 ...
  • 在該文章中,我們基於OpenVINO™ Python API 向大家展示了包含後處理的RT-DETR模型的部署流程,但在實際工業應用中,我們為了與當前軟體平臺集成更多會採用C++平臺,因此在本文中,我們將基於OpenVINO™ C++ API 向大家展示了不包含後處理的RT-DETR模型的部署流程,... ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...