Unity 使用多线程来写日志文件

目的

自动写日志文件功能,但是不能影响游戏性能,故使用多线程来写日志。

源码

/// <summary>
/// 日志文件模块,使用多线程来进行写日志文件
/// </summary>
public class LogFileModule
{
    private static LogFileModule sLogFileModule;
 
    /// <summary>
    /// 开启写日志
    /// </summary>
    public static void Open()
    {
        if (sLogFileModule == null)
        {
            sLogFileModule = new LogFileModule();
        }
    }
 
    public static void Close()
    {
        if (sLogFileModule != null)
        {
            sLogFileModule.Dispose();
            sLogFileModule = null;
        }
    }
 
    #region 私有
 
    private class LogData
    {
        public string log { get; set; }
        public string trace { get; set; }
        public LogType level { get; set; }
    }
 
    private StreamWriter m_StreamWriter;
    private readonly ManualResetEvent m_ManualResetEvent;
    private readonly ConcurrentQueue<LogData> m_ConcurrentQueue; // 安全队列
    private bool m_ThreadRunning;
 
    private LogFileModule()
    {
        var logFileName = string.Format("zysy-logmsg-{0}.log", DateTime.Now.ToString("yyyyMMddHHmmss"));
        var logFilePath = Path.Combine(Application.persistentDataPath, logFileName);
        m_StreamWriter = new StreamWriter(logFilePath);
 
        m_ManualResetEvent = new ManualResetEvent(false);
        m_ConcurrentQueue = new ConcurrentQueue<LogData>();
        m_ThreadRunning = true;
 
        Application.logMessageReceivedThreaded += OnLogMessageReceivedThreaded;
        var fileThread = new Thread(FileLogThread);
        fileThread.Start();
    }
 
    private void Dispose()
    {
        Application.logMessageReceivedThreaded -= OnLogMessageReceivedThreaded;
 
        m_ThreadRunning = false;
        m_ManualResetEvent.Set();
        m_StreamWriter.Close();
        m_StreamWriter = null;
    }
 
    private void OnLogMessageReceivedThreaded(string logString, string stackTrace, LogType type)
    {
        m_ConcurrentQueue.Enqueue(new LogData() { log = logString, trace = stackTrace, level = type });
        m_ManualResetEvent.Set();
    }
 
    private void FileLogThread()
    {
        while (m_ThreadRunning)
        {
            m_ManualResetEvent.WaitOne();
 
            if (m_StreamWriter == null)
            {
                break;
            }
 
            LogData msg;
            while (m_ConcurrentQueue.Count > 0 && m_ConcurrentQueue.TryDequeue(out msg))
            {
                if (msg.level == LogType.Log)
                {
                    m_StreamWriter.Write("LogStart1----");
                    m_StreamWriter.Write(msg.log);
                }
                else if (msg.level == LogType.Warning)
                {
                    m_StreamWriter.Write("LogStart2----");
                    m_StreamWriter.Write(msg.log);
                }
                else
                {
                    m_StreamWriter.Write("LogStart3----");
                    m_StreamWriter.Write(msg.log);
                    m_StreamWriter.Write('\n');
                    m_StreamWriter.Write(msg.trace);
                }
 
                m_StreamWriter.Write("\r\n");
            }
            m_StreamWriter.Flush();
 
            m_ManualResetEvent.Reset();
            Thread.Sleep(1);
        }
    }
 
    #endregion
}

查看器

使用《Unity 控制台 Console 插件增强显示》这个插件,可以导入日志来查看:

Unity使用多线程可以提高游戏的性能和响应速度。但需要注意的是,Unity的所有API都是线程不安全的,所以在使用多线程时,必须采用正确的方式来访问Unity API。 以下是在Unity使用多线程的步骤: 1. 创建新的线程 使用C#的Thread类创建新的线程,如下所示: ``` Thread thread = new Thread(ThreadMethod); thread.Start(); ``` 其中,`ThreadMethod`是新线程要执行的方法。 2. 在新线程中执行逻辑 在新线程中执行复杂的计算或其他需要耗费时间的操作。需要注意的是,在新线程中不能直接访问Unity API。 3. 使用线程安全的方式访问Unity API 为了避免访问Unity API时出现线程安全问题,可以使用以下方法: - 使用线程安全的类型,如ConcurrentQueue,来存储需要在主线程中处理的数据。 - 使用Unity的主线程调用方法,如`UnityMainThreadDispatcher.Instance().Enqueue()`方法,将需要在主线程中执行的代码添加到主线程的执行队列中。 以下是一个使用多线程的示例代码: ``` private ConcurrentQueue<float> queue = new ConcurrentQueue<float>(); private void Update() { float value; while (queue.TryDequeue(out value)) { // 在主线程中处理数据 Debug.Log(value); } } private void ThreadMethod() { for (float i = 0; i < 10000; i++) { queue.Enqueue(i); } } ``` 在上面的示例代码中,我们使用ConcurrentQueue存储需要在主线程中处理的数据。然后在Update方法中不断地尝试从队列中取出数据并在主线程中处理。在新线程中,我们向队列中添加数据。这样可以保证在主线程中处理数据,避免了访问Unity API时出现线程安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值