Thread Ninja说明:

Thread Ninja - Multithread Coroutine

Requires Unity 3.4.0 or higher.

A simple script helps you write multithread coroutines.

Unity's coroutine is great, but it's not a real thread. And a background thread is not allowed to access Unity's API.

Thread Ninja combines coroutine & background thread, make a method both a coroutine and a background thread, makes your life easy with multithread programming.

 
对于yield语句不涉在try...catch中的情况:
     // Use this for initialization
void Start ()
{
GotoState(RunningBaseState.time);
this.StartCoroutineAsync(AsyncCoroutine());
} IEnumerator AsyncCoroutine()
{
while (true)
{
try
{
File.OpenRead("NotExist");
}
catch (Exception e)
{
ZSLoger.Instance.Loger.Debug(e.Message);
}
Thread.Sleep();
yield return ZS.JumpToUnity;
ZSLoger.Instance.Loger.Debug("Jump 2 unity in AsyncCoroutine.");
yield return ZS.JumpBack;
}
}

输出结果:

 
因为yield语句不能在try...catch中的情况修改Task.cs:
 using UnityEngine;
using System.Collections;
using System.Threading; namespace ZSThread
{
/// <summary>
/// Represents an async task.
/// </summary>
public class Task : IEnumerator
{
// implements IEnumerator to make it usable by StartCoroutine;
#region IEnumerator Interface
/// <summary>
/// The current iterator yield return value.
/// </summary>
public object Current { get; private set; } /// <summary>
/// Runs next iteration.
/// </summary>
/// <returns><code>true</code> for continue, otherwise <code>false</code>.</returns>
public bool MoveNext()
{
return OnMoveNext();
} public void Reset()
{
// Reset method not supported by iterator;
throw new System.NotSupportedException(
"Not support calling Reset() on iterator.");
}
#endregion // inner running state used by state machine;
public enum RunningState
{
Init,
RunningAsync,
PendingYield,
ToBackground,
RunningSync,
CancellationRequested,
Done,
Error
} // routine user want to run;
protected readonly IEnumerator _innerRoutine; // current running state;
private RunningState _state;
// last running state;
private RunningState _previousState;
// temporary stores current yield return value
// until we think Unity coroutine engine is OK to get it;
private object _pendingCurrent; /// <summary>
/// Gets state of the task.
/// </summary>
public TaskState State
{
get
{
switch (_state)
{
case RunningState.CancellationRequested:
return TaskState.Cancelled;
case RunningState.Done:
return TaskState.Done;
case RunningState.Error:
return TaskState.Error;
case RunningState.Init:
return TaskState.Init;
default:
return TaskState.Running;
}
}
} /// <summary>
/// Gets exception during running.
/// </summary>
public System.Exception Exception { get; protected set; } public Task(IEnumerator routine)
{
_innerRoutine = routine;
// runs into background first;
_state = RunningState.Init;
} /// <summary>
/// Cancel the task till next iteration;
/// </summary>
public void Cancel()
{
if (State == TaskState.Running)
{
GotoState(RunningState.CancellationRequested);
}
} /// <summary>
/// A co-routine that waits the task.
/// </summary>
public IEnumerator Wait()
{
while (State == TaskState.Running)
yield return null;
} // thread safely switch running state;
protected void GotoState(RunningState state)
{
if (_state == state) return; lock (this)
{
// maintainance the previous state;
_previousState = _state;
_state = state;
}
} // thread safely save yield returned value;
protected void SetPendingCurrentObject(object current)
{
lock (this)
{
_pendingCurrent = current;
}
} // actual MoveNext method, controls running state;
protected bool OnMoveNext()
{
// no running for null;
if (_innerRoutine == null)
return false; // set current to null so that Unity not get same yield value twice;
Current = null; // loops until the inner routine yield something to Unity;
while (true)
{
// a simple state machine;
switch (_state)
{
// first, goto background;
case RunningState.Init:
GotoState(RunningState.ToBackground);
break;
// running in background, wait a frame;
case RunningState.RunningAsync:
return true; // runs on main thread;
case RunningState.RunningSync:
MoveNextUnity();
break; // need switch to background;
case RunningState.ToBackground:
GotoState(RunningState.RunningAsync);
// call the thread launcher;
MoveNextAsync();
return true; // something was yield returned;
case RunningState.PendingYield:
if (_pendingCurrent == ZS.JumpBack)
{
// do not break the loop, switch to background;
GotoState(RunningState.ToBackground);
}
else if (_pendingCurrent == ZS.JumpToUnity)
{
// do not break the loop, switch to main thread;
GotoState(RunningState.RunningSync);
}
else
{
// not from the ZS, then Unity should get noticed,
// Set to Current property to achieve this;
Current = _pendingCurrent; // yield from background thread, or main thread?
if (_previousState == RunningState.RunningAsync)
{
// if from background thread,
// go back into background in the next loop;
_pendingCurrent = ZS.JumpBack;
}
else
{
// otherwise go back to main thread the next loop;
_pendingCurrent = ZS.JumpToUnity;
} // end this iteration and Unity get noticed;
return true;
}
break; // done running, pass false to Unity;
case RunningState.Done:
case RunningState.CancellationRequested:
default:
return false;
}
}
} // background thread launcher;
protected void MoveNextAsync()
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(BackgroundRunner));
} // background thread function;
protected void BackgroundRunner(object state)
{
// just run the sync version on background thread;
MoveNextUnity();
} // run next iteration on main thread;
protected virtual void MoveNextUnity()
{
try
{
// run next part of the user routine;
var result = _innerRoutine.MoveNext(); if (result)
{
// something has been yield returned, handle it;
SetPendingCurrentObject(_innerRoutine.Current);
GotoState(RunningState.PendingYield);
}
else
{
// user routine simple done;
GotoState(RunningState.Done);
}
}
catch (System.Exception ex)
{
// exception handling, save & log it;
this.Exception = ex;
Debug.LogError(string.Format("{0}\n{1}", ex.Message, ex.StackTrace));
// then terminates the task;
GotoState(RunningState.Error);
}
}
}
}

使用情况:

 using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;
using ZSThread; public class RunLogicManager : SingletonLimit<RunLogicManager>
{
private RunningBaseState mState;
private Stack<RunningBaseState> mStateStack = new Stack<RunningBaseState>(); public static RunLogicManager Instance
{
get
{
return (RunLogicManager)mInstance;
}
set
{
mInstance = value;
}
} private void GotoState(RunningBaseState state)
{
if (mStateStack.Count > )
{
var tempState = mStateStack.Pop();
tempState.Exit();
}
mState = state;
mStateStack.Push(mState);
mState.Enter();
} // Use this for initialization
void Start ()
{
GotoState(RunningBaseState.time); ExceptionTask t = new ExceptionTask(AsyncCoroutine(), mono =>
{
ZSLoger.Instance.Loger.Debug("处理异常,此调用处于多线程.");
}, this);
StartCoroutine(t);
} IEnumerator AsyncCoroutine()
{
while (true)
{
File.OpenRead("NotExist");
Thread.Sleep();
yield return ZS.JumpToUnity;
ZSLoger.Instance.Loger.Debug("Jump 2 unity in AsyncCoroutine.");
yield return ZS.JumpBack;
}
} // Update is called once per frame
void Update ()
{ }
} public class ExceptionTask : Task
{
private MonoBehaviour mono;
private UnityAction<MonoBehaviour> exceptionHandle;
public ExceptionTask(IEnumerator routine, UnityAction<MonoBehaviour> exceptionHandle, MonoBehaviour mono) : base(routine)
{
this.mono = mono;
this.exceptionHandle = exceptionHandle;
} // run next iteration on main thread;
protected override void MoveNextUnity()
{
try
{
// run next part of the user routine;
var result = _innerRoutine.MoveNext(); if (result)
{
// something has been yield returned, handle it;
SetPendingCurrentObject(_innerRoutine.Current);
GotoState(RunningState.PendingYield);
}
else
{
// user routine simple done;
GotoState(RunningState.Done);
}
}
catch (System.Exception ex)
{
this.Exception = ex;
//Debug.LogError(string.Format("{0}\n{1}", ex.Message, ex.StackTrace));
ZSLoger.Instance.Loger.Debug("handle exception.");
if (exceptionHandle != null)
{
exceptionHandle.Invoke(mono);
}
// then terminates the task;
GotoState(RunningState.Error);
}
}
}

输出结果:

关于unity协程深度的扩展参考博文:http://blog.csdn.net/ybhjx/article/details/55188777

结合Thread Ninja明确与处理异步协程中的异常的更多相关文章

  1. Swoole 中协程的使用注意事项及协程中的异常捕获

    协程使用注意事项 协程内部禁止使用全局变量,以免发生数据错乱: 协程使用 use 关键字引入外部变量到当前作用域禁止使用引用,以免发生数据错乱: 不能使用类静态变量 Class::$array / 全 ...

  2. python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用

    python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用 一丶单线程+多任务的异步协程 特殊函数 # 如果一个函数的定义被async修饰后,则该函数就是一个特殊的函数 async ...

  3. 【Python3爬虫】使用异步协程编写爬虫

    一.基本概念 进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动.进程是操作系统动态执行的基本单元. 线程:一个进程中包含若干线程,当然至少有一个线程,线程可以利用进程所拥有的资源.线程 ...

  4. 消息/事件, 同步/异步/协程, 并发/并行 协程与状态机 ——从python asyncio引发的集中学习

    我比较笨,只看用await asyncio.sleep(x)实现的例子,看再多,也还是不会. 已经在unity3d里用过coroutine了,也知道是“你执行一下,主动让出权限:我执行一下,主动让出权 ...

  5. python协程与异步协程

    在前面几个博客中我们一一对应解决了消费者消费的速度跟不上生产者,浪费我们大量的时间去等待的问题,在这里,针对业务逻辑比较耗时间的问题,我们还有除了多进程之外更优的解决方式,那就是协程和异步协程.在引入 ...

  6. python爬虫--多任务异步协程, 快点,在快点......

    多任务异步协程asyncio 特殊函数: - 就是async关键字修饰的一个函数的定义 - 特殊之处: - 特殊函数被调用后会返回一个协程对象 - 特殊函数调用后内部的程序语句没有被立即执行 - 协程 ...

  7. Python爬虫进阶 | 异步协程

    一.背景 之前爬虫使用的是requests+多线程/多进程,后来随着前几天的深入了解,才发现,对于爬虫来说,真正的瓶颈并不是CPU的处理速度,而是对于网页抓取时候的往返时间,因为如果采用request ...

  8. 异步协程asyncio+aiohttp

    aiohttp中文文档 1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序 ...

  9. asyncio模块实现单线程-多任务的异步协程

    本篇介绍基于asyncio模块,实现单线程-多任务的异步协程 基本概念 协程函数 协程函数: 定义形式为 async def 的函数; aysnc 在Python3.5+版本新增了aysnc和awai ...

随机推荐

  1. 一、JVM之类加载器

    一.什么是JVM 先来看下百度百科的解释: JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,JVM 是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计 ...

  2. 取Cookie值

    string url_Login_Group = "http://ui.ptlogin2.qq.com/cgi-bin/login?appid=549000912&daid=5&am ...

  3. C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇)

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7551373.html,记录一下学习过程以备后续查用. 一.引言 简单工厂模式并不属于GoF23里面的设计模式 ...

  4. Json与Ajax(注册实例)

    需要在服务器上进行哈 jquery的ajax方法: // jquery请求 $.ajax({ url: "./server/slider.json", type: "po ...

  5. 松软科技课堂:jQuery 效果 - 滑动

    jQuery 滑动方法 通过 jQuery,您可以在元素上创建滑动效果. jQuery 拥有以下滑动方法: slideDown() slideUp() slideToggle() jQuery sli ...

  6. SQL Tuning Health-Check Script (SQLHC) (文档 ID 1366133.1)

    Login to the database server and set the environment used by the Database Instance Download the &quo ...

  7. linux安装docker和docker compose

    运行 sudo -s 切换到root用户. 1.卸载旧版本Docker(如果系统之前没安装过Docker,可以跳过): yum remove docker \ docker-client \ dock ...

  8. 2019kali中文乱码

    1.安装KALI2019.4版本后会出现乱码问题 2.更新国内源,使用vim编辑器修改:vim /etc/apt/sources.list添加 #清华大学 [更新源]    deb https://m ...

  9. 树hash/树哈希 刷题记录

    不同hash姿势: 树的括号序列最小表示法  s[i] 如果i为叶子节点:() 如果i的子节点为j1~jn:(s[j1]...s[jn]),注意s[j]要按照字典序排列

  10. HTML/JavaScript实现地图以鼠标为圆心缩放和移动

    代码如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...