由于程序是3層架構(gòu)的,所有多線程記錄日志成了比較棘手的問題,以前還真就沒有在意過寫日志的問題,認(rèn)為不過是寫文件罷了~~!如今發(fā)現(xiàn)原來要實(shí)現(xiàn)文件共享,并且能夠使多線程同時(shí)操作日志還不能相互沖突,真的很麻煩。當(dāng)然要實(shí)現(xiàn)它我首先想到的是在網(wǎng)上搜,結(jié)果可能是我搜的不得其法,沒發(fā)現(xiàn)結(jié)果,多數(shù)都是用lock,mutx等線程鎖或互斥的方式寫日志,偶想這樣和單線程有啥區(qū)別嗎?還是沒能起到多線程應(yīng)該有的效率!
后來問朋友,發(fā)現(xiàn)個(gè)log4net的東西,不過此物依然用到了線程互斥,看了源碼發(fā)現(xiàn)的!
網(wǎng)絡(luò)不行,朋友不知道,只好自己想辦法。想了幾種方法如下:
1、寫多個(gè)文件,然后找個(gè)機(jī)會(huì)把這些文件合并!
2、干脆放棄寫文件,改寫數(shù)據(jù)庫(kù)!
3、把文件看成一個(gè)表結(jié)構(gòu),實(shí)現(xiàn)行級(jí)鎖。也就是一個(gè)線程寫一行。
4、把文件看成內(nèi)存塊,每塊寫完再合并!
以上幾種方法缺點(diǎn):
1、多個(gè)文件。。。想起來就惡心!
2、寫數(shù)據(jù)庫(kù)?太沒技術(shù)含量咱不干!
3、行級(jí)鎖?我一個(gè)線程要寫入多行不是看起來很亂?
4、沒想到啥缺點(diǎn),實(shí)現(xiàn)它吧!
以下是偶經(jīng)過了10000線程并發(fā)測(cè)試,也沒發(fā)現(xiàn)問題的代碼!
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace MTW
- {
- public class MTWFile
- {
- private string _fileName;
- private static Dictionary<long, long> lockDic = new Dictionary<long, long>();
- /// <summary>
- /// 獲取或設(shè)置文件名稱
- /// </summary>
- public string FileName
- {
- get { return _fileName; }
- set { _fileName = value; }
- }
- /// <summary>
- /// 構(gòu)造函數(shù)
- /// </summary>
- /// <param name="byteCount">每次開辟位數(shù)大小,這個(gè)直接影響到記錄文件的效率</param>
- /// <param name="fileName">文件全路徑名</param>
- public MTWFile(string fileName)
- {
- _fileName = fileName;
- }
- /// <summary>
- /// 創(chuàng)建文件
- /// </summary>
- /// <param name="fileName"></param>
- public void Create(string fileName)
- {
- if (!System.IO.File.Exists(fileName))
- {
- using (System.IO.FileStream fs = System.IO.File.Create(fileName))
- {
- fs.Close();
- }
- }
- }
- /// <summary>
- /// 寫入文本
- /// </summary>
- /// <param name="content">文本內(nèi)容</param>
- private void Write(string content, string newLine)
- {
- if (string.IsNullOrEmpty(_fileName))
- {
- throw new Exception("FileName不能為空!");
- }
- using (System.IO.FileStream fs = new System.IO.FileStream(_fileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite, 8, System.IO.FileOptions.Asynchronous))
- {
- //Byte[] dataArray = System.Text.Encoding.ASCII.GetBytes(System.DateTime.Now.ToString() + content + "/r/n");
- Byte[] dataArray = System.Text.Encoding.Default.GetBytes(content + newLine);
- bool flag = true;
- long slen = dataArray.Length;
- long len = 0;
- while (flag)
- {
- try
- {
- if (len >= fs.Length)
- {
- fs.Lock(len, slen);
- lockDic[len] = slen;
- flag = false;
- }
- else
- {
- len = fs.Length;
- }
- }
- catch (Exception ex)
- {
- while (!lockDic.ContainsKey(len))
- {
- len += lockDic[len];
- }
- }
- }
- fs.Seek(len, System.IO.SeekOrigin.Begin);
- fs.Write(dataArray, 0, dataArray.Length);
- fs.Close();
- }
- }
- /// <summary>
- /// 寫入文件內(nèi)容
- /// </summary>
- /// <param name="content"></param>
- public void WriteLine(string content)
- {
- this.Write(content, System.Environment.NewLine);
- }
- /// <summary>
- /// 寫入文件
- /// </summary>
- /// <param name="content"></param>
- public void Write(string content)
- {
- this.Write(content, "");
- }
- }
- }
調(diào)用起來很簡(jiǎn)單,實(shí)例化,然后隨便調(diào)用一個(gè)write或writeLine方法!
|