unity startunity coroutinee 为什么还很卡顿

StartCoroutine? - Unity Answers
Navigation
Unity account
You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio.
StartCoroutine?
Can anyone explain me about Coroutine. I am not able to understand in .
When you start a coroutine, it's executed until an yield instruction is found. If it's an &empty yield& (returns nothing in JS, or returns null in C#), the coroutine is suspended and control returns to the calling code, as if the coroutine has finished - but it's still alive and kicking! Next frame, the coroutine will wake up automatically in the instruction following the yield, and this will be repeated until the coroutine reaches its last instruction, when it dies silently.
// &empty yield& in JS
// &empty yield& in C#
When you yield to another coroutine, on the other hand, control is passed to this coroutine, and the calling coroutine gets suspended at that yield until the called coroutine finishes:
yield AnotherCoroutine(); // yielding to AnotherCoroutine in JS
yield return StartCoroutine(AnotherCoroutine()); // the same in C#
Each coroutine you start allocates an object in the heap, and will be there until its end is reached. Care must be taken when starting a coroutine in periodic functions like Update, LateUpdate, FixedUpdate etc. because you can crowd the memory with thousands of coroutines executing in parallel - the frame rate drops like a rock, and Unity may even crash when enough coroutines are stealing CPU time and memory. Usually a boolean flag is used to avoid such disasters: you start the coroutine only when the flag is false, set it at the coroutine beginning and clear it at the end, like this:
var executing =
function Update(){
if (executing == false){
StartCoroutine(ACoroutine());
print(&Coroutine started&);
function ACoroutine(): IEnumerator {
executing = // set the flag
yield WaitForSeconds(10.0);
print(&Coroutine ended&);
executing = // clear the flag before returning
This code prints &Coroutine started& at first, and 10 seconds after &Coroutine ended& magically appears in the console, then Update will print &Coroutine started& again, and so on.
If you want an example of how to use a coroutine, take a look at , for instance.
IEnumerator MyCoroutine()
// wait ONE FRAME and continue
// SIC - that's null, not &1& or &frame& or anything else
// wait 5 seconds and continue
yield return new WaitForSeconds(5);
// Custom Update Routine which repeats forever
// wait one frame and continue
yield return 1;
if (IWantToEndEarly)
} while (true);
// end naturally
Hint: You can notify a user about this post by typing @username
Attachments: Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.
14 People are following this question.你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
本帖最后由 追风虫 于
18:21 编辑 _
现在有两个场景 比如 城镇场景 A,刷怪场景 B。A,B场景都10分简单,为了区分分别加了几个盒子。{:101:}
1。场景A,B都是通过如下语句分别打包成A场景、B场景:
BuildPipeline.BuildStreamedSceneAssetBundle(levles,destPath,BuildTarget.StandaloneWindows);
2。加载并切换场景是通过主要如下两个语句:
Application.LoadLevelAsync(sceneName) 或 Application.LoadLeve(sceneName); (这两句都试过)
现在的问题是,当我 每隔一段时间使得 A,B场景切换是没有问题的。
当切换 频率 稍微 高点,就会出现完全 卡死 现象。
查看日记 输出如下:
UnloadTime: 0.782222 ms
Unloading 0 Unused Serialized files (Serialized files now loaded: 0 / Dirty serialized files: 0)
Unloading 33 unused Assets to reduce memory usage. Loaded Objects now: 88.
Total: 1.230323 ms (FindLiveObjects: 0.005307 ms CreateObjectMapping: 0.013968 ms MarkObjects: 0.116215 ms
DeleteObjects: 0.616558 ms)
求大神指点,说下其中原因。{:101:}小弟不胜感激
是卡死现象(整个程序卡死),不是加载慢或者加载卡的现象。
由于可能描述不够清楚,以致大神不知如何下手,现在帖代码如下,代码稍作了些修改,还请不吝赐教:
打包代码如下
--------------分割线---------------------
using UnityE
using System.C
using UnityE
using System.IO;
/// 次脚本为编辑器脚本。
/// 用来打包场景
public class ExportScene
public static void Export_Scene_Each()
Object[] sence = Selection.GetFiltered(typeof(Object),SelectionMode.DeepAssets);
string[] levles =
for(int i = 0; i < sence.L ++ i)
levles_ = AssetDatabase.GetAssetPath(sence_);
for(int i = 0; i < sence.L ++ i)
string destPath = getSceneDestPath(sence_);
BuildPipeline.BuildStreamedSceneAssetBundle(levles,destPath,BuildTarget.StandaloneWindows);
AssetDatabase.Refresh();
private static string getSceneDestPath(Object scene)
string srcPath = AssetDatabase.GetAssetPath(scene);
string sceneAssetRoot = "Scene";
int index_1 = srcPath.LastIndexOf(sceneAssetRoot);
int index_2 = srcPath.LastIndexOf(scene.name);
int len = index_2 - index_1;
string partPath = srcPath.Substring(index_1,len);
/// 目标文件夹的路径,如果没有就创建一个 ///
string destDir = Application.streamingAssetsPath + "/" + partP
if(!Directory.Exists(destDir))
Directory.CreateDirectory(destDir);
/// 如果存在这个文件就删除此文件 ///
string destPath = destDir + scene.name + ".scene";
if(File.Exists(destPath))
File.Delete(destPath);
return destP
场景加载代码如下
--------------分割线---------------------
using UnityE
using System.C
/// A .场景加载代码,有4个场景: 1.有戏最初场景(空场景)2.城镇场景,3怪物场景A,4怪物场景B
/// B .其中 2、3、4场景是被打包的场景
/// C .每个场景摄像机上都挂有此脚本
public class LoadScene_test_2 : MonoBehaviour
void OnGUI()
if(GUILayout.Button("City_scene00"))
StartCoroutine(LoadAssetbundle("testLevel00"));
if(GUILayout.Button("Monster_scene01"))
StartCoroutine(LoadAssetbundle("testLevel01"));
if(GUILayout.Button("Monster_scene02"))
StartCoroutine(LoadAssetbundle("testLevel02"));
private IEnumerator LoadAssetbundle(string sceneName)
string path = "file://" + Application.streamingAssetsPath + "/Scene/" + sceneName + ".scene";
Debug.LogError(path);
WWW m_WWW = new WWW(path);
yield return m_WWW;
if(m_ != null)
Debug.LogError(m_);
AssetBundle bundle = m_WWW .assetB
Application.LoadLevel(sceneName);
bundle.Unload(false);
1、会不会找不到资源? 2、
private WWW m_WWW;
private AssetBundleRequest m_R
public string strDetailedAssetbundleName= "";//要加载总资源包的其中一个具体的资源
private IEnumerator LoadAssetbundle(string path)//在start函数开启 StartCoroutine(LoadAssetbundle("路径"));
m_WWW = new WWW(path);
yield return m_WWW;
AssetBundle bundle = m_WWW .assetB
m_Request = bundle.LoadAsync (strDetailedAssetbundleName, typeof(GameObject));
yield return m_R
bundle.Unload(false);
1、会不会找不到资源? 2、
private WWW m_WWW;
private AssetBundleRequest m_R
public string strDetailedAssetbundleName= "";//要加载总资源包的其中一个具体的资源
private IEnumerator LoadAssetbundle(string path)//在start函数开启 StartCoroutine(LoadAssetbundle("路径"));
m_WWW = new WWW(path);
yield return m_WWW;
AssetBundle bundle = m_WWW .assetB
m_Request = bundle.LoadAsync (strDetailedAssetbundleName, typeof(GameObject));
yield return m_R
bundle.Unload(false);
FSDFSDAFSDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
1、会不会找不到资源? 2、
private WWW m_WWW;
private AssetBundleRequest m_R感谢回复,现在我将我的代码粘贴如上,还请看看有什么问题
感谢回复,现在我将我的代码粘贴如上,还请看看有什么问题
//把这句Application.LoadLevel(“name”);
改成 如下试试 (AssetBundleRequest m_Request ); m_Request = bundle.LoadAsync (strDetailedAssetbundleName, typeof(GameObject));
yield return m_R 非Application.
//把这句Application.LoadLevel(“name”);
改成 如下试试 (AssetBundleRequest m_Request ); m_Re ...额,我试了下你的建议。结果不行:
加载场景要用的是下面这两句的 应该:
Application.LoadLevel(sceneName);
Application.LoadLevelAsync(sceneName);
经过一段时间的纠缠这个问题得到了一定的解决:
解决代码粘贴如下:
编辑器代码
public static void Export_Scene_Each()
Object[] sence = Selection.GetFiltered(typeof(Object),SelectionMode.DeepAssets);
string[] levles =
for(int i = 0; i < sence.L ++ i)
levles = AssetDatabase.GetAssetPath(sence);
for(int i = 0; i < sence.L ++ i)
string destPath = getSceneDestPath(sence);
BuildPipeline.BuildStreamedSceneAssetBundle(new string[]{levles},destPath,BuildTarget.StandaloneWindows);//new string[]{levles}注意这个地方修改
AssetDatabase.Refresh();
加载场景代码
private IEnumerator LoadAssetbundle(string sceneName)
while(!Caching.ready)
Debug.LogError("FFFFFFFFFFFFFFFFFFFFFFFFFF");
string path = "file://" + Application.streamingAssetsPath + "/Scene/" + sceneName + ".scene";
Debug.LogError(path);
WWW m_WWW = new WWW(path);
yield return m_WWW;
if(m_ != null)
Debug.LogError(m_);
AssetBundle bundle = m_
yield return Application.LoadLevelAsync(sceneName);
bundle.Unload(false);
Resources.UnloadUnusedAssets();
不满意的地方{:99:}{:99:}
项目生成.exe后,只能放在全英文目录中。如果放在包含中文目录中场景加载不了。{:98:}{:98:}{:98:}
有没有大神有解决这个问题的方法?{:91:}{:91:}
居然不能选自己为最佳答案,100蛮牛币啊。{:91:}{:91:}
居然不能选自己为最佳答案,100蛮牛币啊。给我点呗给我点呗给我点呗给我点呗给我点呗给我点呗{:97:}
给我点呗给我点呗给我点呗给我点呗给我点呗给我点呗{:91:}恩,给你了{:91:}{:91:}
要回复问题请先或
浏览: 2783
关注: 0 人Unity3D中的Coroutine详解 - 推酷
Unity3D中的Coroutine详解
Unity中的coroutine是通过来实现的。官方脚本中到处会看到这样的代码。
yield是什么?
Coroutine是什么?
unity的coroutine程序执行流程怎么那么奇怪?
unity中的coroutine原理是什么,怎么实现的?
使用unity的coroutine需要注意什么问题?
一、yield的在几种语言中的程序执行特性:
Lua中的yield是使得协同函数运行-&挂起并且传递参数给resume。resume使得协同函数挂起-&运行并且传递参数给协同函数。
C#中yield return/break是用于函数查询集合生成器里面的值(类似迭代)返回,并记录当前现场,下次查询时从上一次记录的yield现场处,继续往下执行,直到继续往下执行没有了,那么退出这段yield的逻辑。yield break会终止掉yield迭代逻辑并跳出。
YieldImplementation:
1).Caller callsfunction
2).Caller requestsitem 按需请求一个元素
3).Next itemreturned 返回请求的元素
4).Goto step #2
Python中的yield expression, 有yield的函数就变成了一个生成器,调用该函数返回的是迭代器对象,用迭代器对象调用next方法(或者循环中会自动调用next方法),才开始执行函数,执行到yield expression处则中断,返回迭代器当前的值,并保留现场,下次调用next则从现场处开始执行,迭代完了就停止了。
可以看出Python中的yield和C#中的yield是类似的,用于创建生成器,执行时中断返回迭代器值,并记录现场,下次从现场处继续执行。
Unity中的yield就是和C#,python中的类似,因为unity是基于.net框架的,且unity脚本开始是用Boo(Python的一个变种)写的。只是unity中多了coroutine类型,和StartCoroutine的coroutine管理类。StartCoroutine不是启动了一个新的线程,而是开启一个协同程序,默认unity所有代码都在一个线程中(
thread-vs-startcoroutine.html)。
二、Unity的Coroutine执行现象:
第一种方法:
voidStart()
print(&Starting & +Time.time);----------------------------------------1
StartCoroutine(WaitAndPrint(2));-------------------------------------2
print(&Done & +Time.time);-------------------------------------------3
IEnumerator WaitAndPrint(float waitTime)
yield return new WaitForSeconds(waitTime);------------------------4
print(&WaitAndPrint & + Time.time);----------------------------------5
该段代码的执行顺序是12435
IEnumerator Start()
print(&Starting & +Time.time);----------------------------------------1
yield return StartCoroutine(WaitAndPrint(2.0F));------------------------2
print(&Done & +Time.time);------------------------------------------3
IEnumerator WaitAndPrint(float waitTime)
yield return new WaitForSeconds(waitTime);----------------------------4
print(&WaitAndPrint & + Time.time);-----------------------------------------5
该段代码的执行顺序是12453
Why?这么奇怪的执行方式。
三、Unity官方文档对coroutine的解释:
Normal coroutine updates are run after theUpdate function returns . Acoroutine is a function that can suspend its execution (yield) until the givenYieldInstruction finishes. Different uses of Coroutines:
yield ; The coroutine will continue after all Update functionshave been called on the next frame .
yield WaitForSeconds(2) ; Continue after a specified time delay , after all Update functions have been called for theframe.
yield WaitForFixedUpdate() ; Continue after all FixedUpdate has been called on all scripts.
yield WWW Continue after a WWW download has completed .
yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to completefirst .
C#要在yield coroutine之间加上return关键字。
四、Unity中的Coroutine原理猜测:
虚拟机分段执行机制, 同类型嵌套用栈存放实现串行执行 :.NET虚拟机在每一帧循环中, 会依次进入每个编译器预定义好的入口。对于Coroutine类型,编译器需要产生一些代码 ,在 Coroutine 类型指定的时间或事件完成后 ( 可通过包含不同 Coroutine 迭代器的多个管理类管理各个 coroutine, coroutine 子类通过多态检查时间或事件到达,所有权交给 coroutine 子类中断的现场; 或是用的 .net 的虚拟机用函数指针进行标记管理现场和在流程中定期检查时间或者事件满足后发生消息,所有权交给 yield 中断的现场 ) ,从 yield 中断后的代码处继续往下执行 , 这样就形成了我们看到的一个function能 分段执行的机制 。
而对于嵌套Coroutine类型,会串行的执行而不是并行的,可能.net虚拟机对于 同 coroutine 类型用栈存放,栈顶的先执行,从而实现串行执行 , 如果外层的不使用 yield return,那么不会串行执行,而是并行执行。
五、Unity中使用Coroutine需要注意的问题:
1.使用的地方和不能使用的地方:
必须在MonoBehaviour或继承于MonoBehaviour的类中调用 yield coroutine。yield不可以在Update或者FixedUpdate里使用。
2.开启协程:
StartCoroutine(string methodName)和StartCoroutine(IEnumeratorroutine)都可以开启一个协程,
使用字符串作为参数时,开启协程时最多只能传递一个参数,并且性能消耗会更大一点; 而使用IEnumerator 作为参数则没有这个限制。
3.删除协程:
1).在Unity3D中,使用StopCoroutine(stringmethodName)来终止该MonoBehaviour指定方法名的一个协同程序,使用StopAllCoroutines()来终止所有该MonoBehaviour可以终止的协同程序。
包括StartCoroutine(IEnumerator routine)的。
2).还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;
如是将协同程序所在脚本的enabled设置为false则不会生效。
4.js和C#中使用区别:
在C#中要使用 yield return而不是yield。
C#中yield(中断)语句必须要在IEnumerator类型里,C#方法的返回类型为IEnumerator,返回值如(eg:yield return new WaitForSeconds(2); 或者 yield returnnull);
5.协程函数返回值和参数类型,组合的设计模式:
协同程序的返回类型为Coroutine类型。在Unity3D中,Coroutine类继承于YieldInstruction,所以,协同程序的返回类型只能为null、等待的帧数(frame)以及等待的时间。
协同程序的参数不能指定ref、out参数。但是,我们在使用WWW类时会经常使用到协同程序,由于在协同程序中不能传递参数地址(引用),也不能输出对象,
这使得每下载一个WWW对象都得重写一个协同程序,解决这个问题的方法是建立一个基于WWW的类( 用组合模式来解决 ),并实现一个下载方法。如下:
using UnityE
using System.C
public class WWWObject : MonoBehaviour
public WWW
public WWWObject(string url)
if(GameVar.wwwCache)
www = WWW.LoadFromCacheOrDownload(url, GameVar.version);
www = new WWW(url);
public IEnumerator Load()
Debug.Log(&Start loading : & + www.url);
while(!www.isDone)
if(GameVar.gameState == GameState.Jumping || GameVar.gameState ==GameState.JumpingAsync)
LoadScene.progress = www.
yield return 1;
if(www.error != null)
Debug.LogError(&Loading error : & + www.url + &\n& +www.error);
Debug.Log(&End loading : & + www.url);
public IEnumerator LoadWithTip(string resourcesName)
Debug.Log(&Start loading : & + www.url);
LoadScene.tipStr =&&Downloading& resources&& + resourcesName + && . . .&;
while(!www.isDone)
if(GameVar.gameState == GameState.Jumping || GameVar.gameState ==GameState.JumpingAsync)
LoadScene.progress= www.
yield return 1;
if(www.error != null)
Debug.LogError(&Loading error : & + www.url + &\n& +www.error);
Debug.Log(&End loading : & + www.url);
using UnityE
using System.C
using System.Collections.G
public class LoadResources : MonoBehaviour
static string url =&http://61.149.211.88/Package/test.unity3d&;
public static WWW www =
IEnumerator Start()
if(!GameVar.resourcesLoaded)
GameVar.gameState = GameState.J
WWWObject obj = new WWWObject(url);
www = obj.
yield return StartCoroutine(obj.LoadWithTip(&Textures&));
GameVar.resourcesLoaded =
GameVar.gameState = GameState.R
参考文章:
/forum/read.php?tid=13148
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 unity stopcoroutine 的文章

 

随机推荐