Best practices: Async vs. coroutines - Unite Copenhagen
// UnityMultithreading//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
public class ThreadQueuer : MonoBehaviour
{
void Start()
{
// BIG HUGE NOTE: WebGL doesn't do multithreading.
Debug.Log("Start() -- Started.");
functionsToRunInMainThread = new List<Action>();
StartThreadedFunction( () => { SlowFunctionThatDoesAUnityThing( Vector3.zero, new float[4], new Color[100] ); } );
Debug.Log("Start() -- Done.");
}
void Update()
{
// Update() always runs in the main thread
while(functionsToRunInMainThread.Count > 0)
{
// Grab the first/oldest function in the list
Action someFunc = functionsToRunInMainThread[0];
functionsToRunInMainThread.RemoveAt(0);
// Now run it
someFunc();
}
}
List<Action> functionsToRunInMainThread;
public void StartThreadedFunction( Action someFunctionWithNoParams )
{
Thread t = new Thread( new ThreadStart( someFunctionWithNoParams ) );
t.Start();
}
public void QueueMainThreadFunction( Action someFunction )
{
// We need to make sure that someFunction is running from the
// main thread
//someFunction(); // This isn't okay, if we're in a child thread
functionsToRunInMainThread.Add(someFunction);
}
void SlowFunctionThatDoesAUnityThing( Vector3 foo, float[] bar, Color[] pixels )
{
// First we do a really slow thing
Thread.Sleep(2000); // Sleep for 2 seconds
// Now we need to modify a Unity gameobject
Action aFunction = () => {
Debug.Log("The results of the child thread are being applied to a Unity GameObject safely.");
this.transform.position = new Vector3(1,1,1); // NOT ALLOWED FROM A CHILD THREAD
};
// NOTE: We still aren't allowed to call this from a child thread
//aFunction();
QueueMainThreadFunction( aFunction );
}
}
http://quill18.com/unity_tutorials/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class ExampleScript : MonoBehaviour
{
void Start ()
{
Debug.Log("Start() :: Starting.");
foo = "Computer Science";
someVector = new Vector3(1, 1, 1);
// SlowJob is a variable that contains some function code
// When you add the () at the end of the SlowJob variable
// name, that's a shortcut to tell C# "execute the contents of variable SlowJob"
myThread = new Thread( SlowJob );
// Now run SlowJob in a new thread
myThread.Start();
Debug.Log("Start() :: Done.");
}
Thread myThread;
void Update()
{
if( myThread.IsAlive )
{
Debug.Log("SlowJob isRunning");
}
else
{
// The thread is done, so copy the pixels back to the texture
someTexture.SetPixels(pixels);
}
someVector = new Vector3(2, 2, 2);
Vector3 pos = this.transform.position;
pos.x = 3;
this.transform.position = pos;
//this.transform.Translate( Vector3.up * Time.deltaTime );
pixels = someTexture.GetPixels();
}
Texture2D someTexture;
Color[] pixels;
void PrintStudentID()
{
// This send "foo" to the printer
// This should print out "Computer Science"
// Or maybe it'll print out "English Literature"
// Either is legit
// What isn't legit is if in the MIDDDLE of printing, the
// other thread makes a change and suddenly we get a
// student ID that says: "Compute Literature"
// Let's make sure no one is changing our data mid-way through
// our printing operation.
lock(FrontDoor)
{
// Print out the student ID here, safe in the
// knowledge that nothing is messing with our data.
}
}
void FixedUpdate()
{
}
string foo;
Vector3 someVector;
object FrontDoor = new object();
void SlowJob()
{
Debug.Log("ExampleScript::SlowJob() -- Doing 1000 things, each taking 2ms.");
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
someVector = new Vector3(0, 0, 0);
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(2); // Sleep for 2ms
}
sw.Stop();
// NOTE: Because of various overheads and context-switches, elapsed time
// will be slightly more than 2 seconds.
Debug.Log("ExampleScript::SlowJob() -- Done! Elapsed time: " + sw.ElapsedMilliseconds/1000f);
}
}
其他的loom
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
public class Loom :MonoBehaviour
{
public static int maxThreads = 8;
static int numThreads;
private static Loom _current;
//private int _count;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
void Awake()
{
_current = this;
initialized = true;
}
static bool initialized;
public static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
#if !ARTIST_BUILD
UnityEngine.Object.DontDestroyOnLoad(g);
#endif
}
}
public struct NoDelayedQueueItem
{
public Action<object> action;
public object param;
}
private List<NoDelayedQueueItem> _actions = new List<NoDelayedQueueItem>();
public struct DelayedQueueItem
{
public float time;
public Action<object> action;
public object param;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action<object> taction, object tparam)
{
QueueOnMainThread(taction, tparam, 0f);
}
public static void QueueOnMainThread(Action<object> taction, object tparam, float time)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = taction, param = tparam });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(new NoDelayedQueueItem { action = taction, param = tparam });
}
}
}
public static Thread RunAsync(Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(100);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return null;
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Use this for initialization
void Start()
{
}
List<NoDelayedQueueItem> _currentActions = new List<NoDelayedQueueItem>();
// Update is called once per frame
void Update()
{
if (_actions.Count > 0)
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
for (int i = 0; i < _currentActions.Count; i++)
{
_currentActions[i].action(_currentActions[i].param);
}
}
if (_delayed.Count > 0)
{
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
for (int i = 0; i < _currentDelayed.Count; i++)
{
_delayed.Remove(_currentDelayed[i]);
}
}
for (int i = 0; i < _currentDelayed.Count; i++)
{
_currentDelayed[i].action(_currentDelayed[i].param);
}
}
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Threading;
public class testLoom : MonoBehaviour
{
public Text mText;
void Start ()
{
// 用Loom的方法调用一个线程
Loom.RunAsync(
() =>
{
Thread thread = new Thread(RefreshText);
thread.Start();
}
);
}
void Update ()
{
}
private void RefreshText()
{
// 用Loom的方法在Unity主线程中调用Text组件
Loom.QueueOnMainThread((param) =>
{
mText.text = "Hello Loom!";
},null);
}
}