網站首頁 編程語言 正文
一、簡介
在開發程序的過程中,難免少不了寫入錯誤日志這個關鍵功能。實現這個功能,可以選擇使用第三方日志插件,也可以選擇使用數據庫,還可以自己寫個簡單的方法把錯誤信息記錄到日志文件。現在我們來講下最后一種方法:
在選擇最后一種方法實現的時候,若對文件操作與線程同步不熟悉,問題就有可能出現了,因為同一個文件并不允許多個線程同時寫入,否則會提示“文件正在由另一進程使用,因此該進程無法訪問此文件”。這是文件的并發寫入問題,就需要用到線程同步。而微軟也給線程同步提供了一些相關的類可以達到這樣的目的,本文使用到的 System.Threading.ReaderWriterLockSlim 便是其中之一。該類用于管理資源訪問的鎖定狀態,可實現多線程讀取或進行獨占式寫入訪問。利用這個類,我們就可以避免在同一時間段內多線程同時寫入一個文件而導致的并發寫入問題。讀寫鎖是以 ReaderWriterLockSlim 對象作為鎖管理資源的,不同的 ReaderWriterLockSlim 對象中鎖定同一個文件也會被視為不同的鎖進行管理,這種差異可能會再次導致文件的并發寫入問題,所以 ReaderWriterLockSlim 應盡量定義為只讀的靜態對象。
ReaderWriterLockSlim 有幾個關鍵的方法,本文僅討論寫入鎖:
1.調用 EnterWriteLock 方法 進入寫入狀態,在調用線程進入鎖定狀態之前一直處于阻塞狀態,因此可能永遠都不返回。
2.調用 TryEnterWriteLock 方法 進入寫入狀態,可指定阻塞的間隔時間,如果調用線程在此間隔期間并未進入寫入模式,將返回false。
3.調用 ExitWriteLock 方法 退出寫入狀態,應使用 finally 塊執行 ExitWriteLock 方法,從而確保調用方退出寫入模式。
二、不使用讀寫鎖寫入文件:
代碼:
class Program
{
static int LogCount = 100;
static int WritedCount = 0;
static int FailedCount = 0;
static void Main(string[] args)
{
//迭代運行寫入日志記錄,由于多個線程同時寫入同一個文件將會導致錯誤
Parallel.For(0, LogCount, e =>
{
WriteLog1();
});
Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
Console.Read();
}
#region 未加入讀寫鎖
//不使用讀寫鎖寫入文件
static void WriteLog1()
{
try
{
var logFilePath = "log.txt";
var now = DateTime.Now;
var logContent = string.Format("Tid: {0}{1} {2}.{3}\r\n", Thread.CurrentThread.ManagedThreadId.ToString().PadRight(4), now.ToLongDateString(), now.ToLongTimeString(), now.Millisecond.ToString());
File.AppendAllText(logFilePath, logContent);
WritedCount++;
}
catch (Exception ex)
{
FailedCount++;
Console.WriteLine(ex.Message);
}
}
#endregion
}
運行結果:
不是所有的log都能寫入到log.txt,因為不適用讀寫錯可能會出現上面提到的:“文件正在由另一進程使用,因此該進程無法訪問此文件”報錯信息。
記錄log信息:
Tid: 9 2021年5月21日 下午 02:18:04.919
Tid: 9 2021年5月21日 下午 02:18:04.944
Tid: 9 2021年5月21日 下午 02:18:05.80
Tid: 11 2021年5月21日 下午 02:18:05.81
Tid: 9 2021年5月21日 下午 02:18:05.82
Tid: 12 2021年5月21日 下午 02:18:05.83
Tid: 11 2021年5月21日 下午 02:18:05.84
Tid: 12 2021年5月21日 下午 02:18:05.84
Tid: 16 2021年5月21日 下午 02:18:05.85
Tid: 12 2021年5月21日 下午 02:18:05.111
Tid: 16 2021年5月21日 下午 02:18:05.117
Tid: 16 2021年5月21日 下午 02:18:05.128
Tid: 11 2021年5月21日 下午 02:18:05.128
Tid: 16 2021年5月21日 下午 02:18:05.133
Tid: 12 2021年5月21日 下午 02:18:05.138
Tid: 16 2021年5月21日 下午 02:18:05.140
Tid: 12 2021年5月21日 下午 02:18:05.140
Tid: 16 2021年5月21日 下午 02:18:05.142
Tid: 16 2021年5月21日 下午 02:18:05.144
Tid: 16 2021年5月21日 下午 02:18:05.151
Tid: 16 2021年5月21日 下午 02:18:05.158
Tid: 9 2021年5月21日 下午 02:18:05.159
Tid: 10 2021年5月21日 下午 02:18:05.159
Tid: 9 2021年5月21日 下午 02:18:05.164
Tid: 16 2021年5月21日 下午 02:18:05.164
Tid: 9 2021年5月21日 下午 02:18:05.172
Tid: 15 2021年5月21日 下午 02:18:05.172
Tid: 16 2021年5月21日 下午 02:18:05.181
Tid: 16 2021年5月21日 下午 02:18:05.187
Tid: 15 2021年5月21日 下午 02:18:05.188
Tid: 16 2021年5月21日 下午 02:18:05.195
Tid: 16 2021年5月21日 下午 02:18:05.196
Tid: 15 2021年5月21日 下午 02:18:05.195
Tid: 16 2021年5月21日 下午 02:18:05.202
Tid: 16 2021年5月21日 下午 02:18:05.203
Tid: 15 2021年5月21日 下午 02:18:05.202
Tid: 15 2021年5月21日 下午 02:18:05.207
Tid: 15 2021年5月21日 下午 02:18:05.209
Tid: 16 2021年5月21日 下午 02:18:05.207
Tid: 15 2021年5月21日 下午 02:18:05.210
Tid: 15 2021年5月21日 下午 02:18:05.222
Tid: 15 2021年5月21日 下午 02:18:05.231
Tid: 18 2021年5月21日 下午 02:18:05.238
Tid: 15 2021年5月21日 下午 02:18:05.238
Tid: 18 2021年5月21日 下午 02:18:05.244
Tid: 15 2021年5月21日 下午 02:18:05.251
Tid: 15 2021年5月21日 下午 02:18:05.256
Tid: 15 2021年5月21日 下午 02:18:05.262
Tid: 15 2021年5月21日 下午 02:18:05.304
Tid: 15 2021年5月21日 下午 02:18:05.312
Tid: 13 2021年5月21日 下午 02:18:05.312
Tid: 9 2021年5月21日 下午 02:18:05.313
Tid: 13 2021年5月21日 下午 02:18:05.320
Tid: 19 2021年5月21日 下午 02:18:05.320
Tid: 16 2021年5月21日 下午 02:18:05.325
Tid: 19 2021年5月21日 下午 02:18:05.333
Tid: 16 2021年5月21日 下午 02:18:05.342
Tid: 16 2021年5月21日 下午 02:18:05.349
Tid: 16 2021年5月21日 下午 02:18:05.361
Tid: 16 2021年5月21日 下午 02:18:05.366
Tid: 16 2021年5月21日 下午 02:18:05.367
Tid: 16 2021年5月21日 下午 02:18:05.368
Tid: 16 2021年5月21日 下午 02:18:05.376
Tid: 16 2021年5月21日 下午 02:18:05.386
Tid: 16 2021年5月21日 下午 02:18:05.392
Tid: 16 2021年5月21日 下午 02:18:05.401
Tid: 9 2021年5月21日 下午 02:18:05.463
Tid: 13 2021年5月21日 下午 02:18:05.464
Tid: 15 2021年5月21日 下午 02:18:05.464
Tid: 13 2021年5月21日 下午 02:18:05.465
Tid: 13 2021年5月21日 下午 02:18:05.470
Tid: 11 2021年5月21日 下午 02:18:05.479
三、使用讀寫鎖寫入文件:
代碼:
class Program
{
static int LogCount = 100;
static int WritedCount = 0;
static int FailedCount = 0;
static void Main(string[] args)
{
//迭代運行寫入日志記錄,由于多個線程同時寫入同一個文件將會導致錯誤
Parallel.For(0, LogCount, e =>
{
WriteLog2();
});
Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
Console.Read();
}
#region 加入讀寫鎖
//讀寫鎖,當資源處于寫入模式時,其他線程寫入需要等待本次寫入結束之后才能繼續寫入
static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
static void WriteLog2()
{
try
{
//設置讀寫鎖為寫入模式獨占資源,其他寫入請求需要等待本次寫入結束之后才能繼續寫入
//注意:長時間持有讀線程鎖或寫線程鎖會使其他線程發生饑餓 (starve)。 為了得到最好的性能,需要考慮重新構造應用程序以將寫訪問的持續時間減少到最小。
//從性能方面考慮,請求進入寫入模式應該緊跟文件操作之前,在此處進入寫入模式僅是為了降低代碼復雜度
//因進入與退出寫入模式應在同一個try finally語句塊內,所以在請求進入寫入模式之前不能觸發異常,否則釋放次數大于請求次數將會觸發異常
LogWriteLock.EnterWriteLock();
var logFilePath = "log.txt";
var now = DateTime.Now;
var logContent = string.Format("Tid: {0}{1} {2}.{3}\r\n", Thread.CurrentThread.ManagedThreadId.ToString().PadRight(4), now.ToLongDateString(), now.ToLongTimeString(), now.Millisecond.ToString());
File.AppendAllText(logFilePath, logContent);
WritedCount++;
}
catch (Exception)
{
FailedCount++;
}
finally
{
//退出寫入模式,釋放資源占用
//注意:一次請求對應一次釋放
//若釋放次數大于請求次數將會觸發異常[寫入鎖定未經保持即被釋放]
//若請求處理完成后未釋放將會觸發異常[此模式不下允許以遞歸方式獲取寫入鎖定]
LogWriteLock.ExitWriteLock();
}
}
#endregion
}
運行結果:
所有的log都完全正確寫入到log.txt。
記錄log信息:
Tid: 8 2021年5月21日 下午 02:26:36.573
Tid: 8 2021年5月21日 下午 02:26:36.597
Tid: 8 2021年5月21日 下午 02:26:36.599
Tid: 8 2021年5月21日 下午 02:26:36.600
Tid: 8 2021年5月21日 下午 02:26:36.601
Tid: 8 2021年5月21日 下午 02:26:36.602
Tid: 8 2021年5月21日 下午 02:26:36.608
Tid: 8 2021年5月21日 下午 02:26:36.609
Tid: 8 2021年5月21日 下午 02:26:36.614
Tid: 8 2021年5月21日 下午 02:26:36.616
Tid: 8 2021年5月21日 下午 02:26:36.617
Tid: 8 2021年5月21日 下午 02:26:36.620
Tid: 8 2021年5月21日 下午 02:26:36.620
Tid: 8 2021年5月21日 下午 02:26:36.621
Tid: 8 2021年5月21日 下午 02:26:36.622
Tid: 8 2021年5月21日 下午 02:26:36.623
Tid: 8 2021年5月21日 下午 02:26:36.624
Tid: 8 2021年5月21日 下午 02:26:36.624
Tid: 8 2021年5月21日 下午 02:26:36.625
Tid: 8 2021年5月21日 下午 02:26:36.626
Tid: 8 2021年5月21日 下午 02:26:36.626
Tid: 8 2021年5月21日 下午 02:26:36.627
Tid: 8 2021年5月21日 下午 02:26:36.628
Tid: 8 2021年5月21日 下午 02:26:36.628
Tid: 8 2021年5月21日 下午 02:26:36.629
Tid: 8 2021年5月21日 下午 02:26:36.630
Tid: 8 2021年5月21日 下午 02:26:36.630
Tid: 8 2021年5月21日 下午 02:26:36.631
Tid: 8 2021年5月21日 下午 02:26:36.632
Tid: 8 2021年5月21日 下午 02:26:36.632
Tid: 8 2021年5月21日 下午 02:26:36.633
Tid: 8 2021年5月21日 下午 02:26:36.634
Tid: 8 2021年5月21日 下午 02:26:36.634
Tid: 8 2021年5月21日 下午 02:26:36.635
Tid: 8 2021年5月21日 下午 02:26:36.636
Tid: 8 2021年5月21日 下午 02:26:36.636
Tid: 8 2021年5月21日 下午 02:26:36.637
Tid: 8 2021年5月21日 下午 02:26:36.638
Tid: 8 2021年5月21日 下午 02:26:36.638
Tid: 8 2021年5月21日 下午 02:26:36.639
Tid: 8 2021年5月21日 下午 02:26:36.641
Tid: 8 2021年5月21日 下午 02:26:36.641
Tid: 8 2021年5月21日 下午 02:26:36.642
Tid: 8 2021年5月21日 下午 02:26:36.643
Tid: 8 2021年5月21日 下午 02:26:36.644
Tid: 8 2021年5月21日 下午 02:26:36.644
Tid: 8 2021年5月21日 下午 02:26:36.645
Tid: 8 2021年5月21日 下午 02:26:36.646
Tid: 8 2021年5月21日 下午 02:26:36.647
Tid: 8 2021年5月21日 下午 02:26:36.647
Tid: 8 2021年5月21日 下午 02:26:36.648
Tid: 8 2021年5月21日 下午 02:26:36.649
Tid: 8 2021年5月21日 下午 02:26:36.650
Tid: 8 2021年5月21日 下午 02:26:36.650
Tid: 8 2021年5月21日 下午 02:26:36.651
Tid: 8 2021年5月21日 下午 02:26:36.652
Tid: 8 2021年5月21日 下午 02:26:36.652
Tid: 8 2021年5月21日 下午 02:26:36.652
Tid: 8 2021年5月21日 下午 02:26:36.653
Tid: 8 2021年5月21日 下午 02:26:36.654
Tid: 8 2021年5月21日 下午 02:26:36.655
Tid: 8 2021年5月21日 下午 02:26:36.656
Tid: 8 2021年5月21日 下午 02:26:36.658
Tid: 8 2021年5月21日 下午 02:26:36.658
Tid: 8 2021年5月21日 下午 02:26:36.659
Tid: 8 2021年5月21日 下午 02:26:36.660
Tid: 8 2021年5月21日 下午 02:26:36.660
Tid: 8 2021年5月21日 下午 02:26:36.661
Tid: 8 2021年5月21日 下午 02:26:36.662
Tid: 8 2021年5月21日 下午 02:26:36.662
Tid: 8 2021年5月21日 下午 02:26:36.663
Tid: 8 2021年5月21日 下午 02:26:36.664
Tid: 8 2021年5月21日 下午 02:26:36.664
Tid: 8 2021年5月21日 下午 02:26:36.665
Tid: 8 2021年5月21日 下午 02:26:36.666
Tid: 8 2021年5月21日 下午 02:26:36.666
Tid: 8 2021年5月21日 下午 02:26:36.667
Tid: 8 2021年5月21日 下午 02:26:36.668
Tid: 8 2021年5月21日 下午 02:26:36.669
Tid: 8 2021年5月21日 下午 02:26:36.669
Tid: 8 2021年5月21日 下午 02:26:36.670
Tid: 8 2021年5月21日 下午 02:26:36.671
Tid: 8 2021年5月21日 下午 02:26:36.672
Tid: 8 2021年5月21日 下午 02:26:36.673
Tid: 8 2021年5月21日 下午 02:26:36.675
Tid: 8 2021年5月21日 下午 02:26:36.675
Tid: 8 2021年5月21日 下午 02:26:36.676
Tid: 8 2021年5月21日 下午 02:26:36.677
Tid: 14 2021年5月21日 下午 02:26:36.678
Tid: 15 2021年5月21日 下午 02:26:36.679
Tid: 16 2021年5月21日 下午 02:26:36.680
Tid: 17 2021年5月21日 下午 02:26:36.681
Tid: 18 2021年5月21日 下午 02:26:36.681
Tid: 20 2021年5月21日 下午 02:26:36.683
Tid: 9 2021年5月21日 下午 02:26:36.683
Tid: 19 2021年5月21日 下午 02:26:36.684
Tid: 10 2021年5月21日 下午 02:26:36.685
Tid: 11 2021年5月21日 下午 02:26:36.685
Tid: 12 2021年5月21日 下午 02:26:36.687
Tid: 13 2021年5月21日 下午 02:26:36.688
原文鏈接:https://www.cnblogs.com/wml-it/p/14793662.html
相關推薦
- 2022-05-21 一次線上mongo慢查詢問題排查處理記錄_MongoDB
- 2022-08-31 Postgresql數據庫character?varying和character的區別說明_Post
- 2022-09-09 Go語言提升開發效率的語法糖技巧分享_Golang
- 2022-03-27 Unity實現物體跟隨鼠標移動_C#教程
- 2022-09-03 Python?Pandas中DataFrame.drop_duplicates()刪除重復值詳解_p
- 2023-04-26 詳解Flutter桌面應用如何進行多分辨率適配_Android
- 2022-10-30 Android?Studio調試Gradle插件詳情_Android
- 2023-07-05 實際開發中如何存儲密碼(md5加鹽bcrypt)golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支