又一周了,最近的生活,hhhe, 学习的过程真的是非常非常缓慢的,不过慢慢的,不急,不怕,不怂。
最近写某个东西,封装了一个数据库操作的包,可是有个大bug,暂时不贴出来,因为还没有解决。但是封装了这个log包,其实没写完整的,不过感觉还好,反正比即时log好。
顺便说说,这个操作做缓存,为什么?其实原因非常简单,这就用到操作系统的知识了。因为当我们执行写数据库,或者写日志到文件的时候,会发生io中断,io中断会让操作系统来处理这些中断,这时我们的程序执行时,就会从用户级切换到核心级,处理结束后再从核心级返回到用户级,这一个转换过程的代价是很大的,当频繁执行这样的操作,整个系统的性能会非常的差,这些都助攻于以前写遗传算法算皇后问题时,在遗传迭代的过程中有使用到 C++ 的cout ,于是8皇后都需要5,6秒,16 皇后要跑好几分钟,原来一直以为是算法问题,找了好久好久,突然反应过来cout的io中断,注释掉以后,全是秒执行。这就io操作的代价。
还有这也有助于高并发的处理,这一部分之后再说,我还有些问题没有解决。
接下来说说log日志实现,也很简单,当需要打印某条日志时,先将日志信息保存在内存中,而不是立即打印,如果在一段时间内又有其他日志信息需要打印,就将所有的日志信息一起拼接起来,一起写入文件。一次写多多条语句到文件的效率比多次写入一条的效率高出NNNNNNN倍了。
贴贴自己封装的log包,不完整版,之后使用的过程中,完善了会更新。
封装的包,感觉代码风格挺不错,哈哈哈
package mylog
import (
"log"
"os"
"fmt"
"time"
"runtime"
"strconv"
)
var fileStr LogFileInfo
var logType LogType
var logBuffer LogBuffer
func Init() {
fileStr = LogFileInfo{}
logType = LogType{}
logBuffer = LogBuffer{}
logBufferInit()
defineLogType()
defineLogInfo()
go autoLog()
}
func logBufferInit() {
logBuffer.Log = []string{}
logBuffer.Assert = []string{}
logBuffer.Warning = []string{}
logBuffer.Error = []string{}
logBuffer.Exception = []string{}
}
func defineLogType() {
filename := "mylog/logTxt.txt"
fPtr, err := createLogFile(filename)
if err != nil {
fmt.Println(err)
//失败了怎么办,应该不允许失败这里
}
fileStr.logTxt = fPtr
filename = "mylog/assTxt.txt"
fPtr, err = createLogFile(filename)
if err != nil {
fmt.Println(err)
//失败了怎么办,应该不允许失败这里
}
fileStr.assTxt = fPtr
filename = "mylog/warTxt.txt"
fPtr, err = createLogFile(filename)
if err != nil {
fmt.Println(err)
//失败了怎么办,应该不允许失败这里
}
fileStr.warTxt = fPtr
filename = "mylog/errTxt.txt"
fPtr, err = createLogFile(filename)
if err != nil {
fmt.Println(err)
//失败了怎么办,应该不允许失败这里
}
fileStr.errTxt = fPtr
filename = "mylog/excTxt.txt"
fPtr, err = createLogFile(filename)
if err != nil {
fmt.Println(err)
//失败了怎么办,应该不允许失败这里
}
fileStr.excTxt = fPtr
}
func createLogFile(filename string) (*os.File, error) {
if _, err := os.Stat(filename); err != nil {
file, err := os.Create(filename)
if err != nil {
return nil, err
}
return file, nil
} else {
file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND, os.ModePerm)
if err != nil {
return nil, err
}
return file, nil
}
}
func defineLogInfo() {
logType.LogLog = log.New(fileStr.logTxt, "", 0)
logType.LogAssert = log.New(fileStr.assTxt, "", 0)
logType.LogWar = log.New(fileStr.warTxt, "", 0)
logType.LogErr = log.New(fileStr.errTxt, "", 0)
logType.LogException = log.New(fileStr.excTxt, "", 0)
}
func GetLog() *LogType {
if fileStr.logTxt == nil || fileStr.assTxt == nil || fileStr.warTxt == nil || fileStr.errTxt == nil || fileStr.excTxt == nil {
fmt.Println("fileStr has invalid pointer or nil ptr", fileStr)
logType.LogWar.Println("fileStr has invalid pointer or nil ptr")
}
return &logType
}
func autoLog() {
for {
bufferLength := 0
bufferLength += checkBuffer(&logBuffer.Log, 1)
bufferLength += checkBuffer(&logBuffer.Assert, 2)
bufferLength += checkBuffer(&logBuffer.Warning, 4)
bufferLength += checkBuffer(&logBuffer.Error, 8)
bufferLength += checkBuffer(&logBuffer.Exception, 16)
if bufferLength == 0 {
time.Sleep(4 * time.Second)
}
}
}
func checkBuffer(str *[]string, parame int) int {
length := len((*str))
if length != 0 {
buffer := (*str)[0:length]
logInfo := ""
for i := 0; i < length; i++ {
logInfo = logInfo + buffer[i] + "\r\n"
}
//@parame & 速度最快
if parame & 1 != 0 {
logType.LogLog.Println(logInfo)
} else if parame & 2 != 0 {
logType.LogAssert.Println(logInfo)
} else if parame & 4 != 0 {
logType.LogWar.Println(logInfo)
} else if parame & 8 != 0 {
logType.LogErr.Println(logInfo)
} else if parame & 16 != 0 {
logType.LogException.Println(logInfo)
}
length2 := len((*str))
if length2 != length {
(*str) = (*str)[length:length2]
return len(*str)
} else {
(*str) = (*str)[:0]
}
}
return 0
}
//@logFormat
//[log]: 2016/03/24 01:02:04 /Users/tangs/IdeaProjects/MoodleServe3/mylog/log.go:150: logBuffer.Log
//runtime.Caller(Depth)
//Depth should be 1, 2 or bigger.How finish it.
func AddLog (msg string) {
_, file, line, ok := runtime.Caller(1)
s := ""
if ok {
t := time.Now()
s = "[Log] : " + t.String() + " " + file + ":" + strconv.Itoa(line)
}
msg = s + " " + msg
logBuffer.Log = append(logBuffer.Log, msg)
}
func AddAssert (msg string) {
_, file, line, ok := runtime.Caller(1)
s := ""
if ok {
t := time.Now()
s = "[Assert] : " + t.String() + " " + file + ":" + strconv.Itoa(line)
}
msg = s + " " + msg
logBuffer.Assert = append(logBuffer.Assert, msg)
}
func AddWarning (msg string) {
_, file, line, ok := runtime.Caller(1)
s := ""
if ok {
t := time.Now()
s = "[Warning] : " + t.String() + " " + file + ":" + strconv.Itoa(line)
}
msg = s + " " + msg
logBuffer.Warning = append(logBuffer.Warning, msg)
}
func AddError(msg string) {
_, file, line, ok := runtime.Caller(1)
s := ""
if ok {
t := time.Now()
s = "[Error] : " + t.String() + " " + file + ":" + strconv.Itoa(line)
}
msg = s + " " + msg
logBuffer.Error = append(logBuffer.Error, msg)
}
func AddException(msg string) {
_, file, line, ok := runtime.Caller(1)
s := ""
if ok {
t := time.Now()
s = "[Exception] : " + t.String() + " " + file + ":" + strconv.Itoa(line)
}
msg = s + " " + msg
logBuffer.Exception = append(logBuffer.Exception, msg)
}
func Flush() {
//todo 立即将缓存写入文件
}
定义的结构体,
package mylog
import (
"log"
"os"
)
type LogType struct {
LogLog *log.Logger //用于错误的日志类型。
LogAssert *log.Logger //用于断言(Assert)的日志类型(这些表明Unity自身的一个错误)。
LogWar *log.Logger //用于警告(Warning)的日志类型。
LogErr *log.Logger //用于普通日志消息的日志类型。
LogException *log.Logger //用于异常的日志类型。
}
type LogFileInfo struct {
logTxt *os.File
assTxt *os.File
warTxt *os.File
errTxt *os.File
excTxt *os.File
}
type LogBuffer struct {
Log []string
Assert []string
Warning []string
Error []string
Exception []string
}
有疑问加站长微信联系(非本文作者)