एकता सुरक्षित नहीं Thread
है, तो वे यह असंभव है, जब इसके एपीआई एक और Thread
से प्रयोग किया जाता है एक अपवाद फेंकने के लिए एक तंत्र जोड़कर एक और Thread
से उनके एपीआई कॉल करने के लिए बनाने का फैसला किया।
इस प्रश्न से कई बार पूछा गया है, लेकिन उनमें से किसी के लिए कोई उचित समाधान/उत्तर नहीं दिया गया है। उत्तर आमतौर पर "प्लगइन का उपयोग करते हैं" या कुछ थ्रेड-सुरक्षित नहीं करते हैं। उम्मीद है कि यह आखिरी होगा।
समाधान जो आप आमतौर पर स्टैक ओवरफ्लो या यूनिटी की फोरम वेबसाइट पर देखते हैं, वह केवल boolean
वैरिएबल का उपयोग करने के लिए मुख्य थ्रेड को यह जानने के लिए है कि आपको मुख्य Thread
में कोड निष्पादित करने की आवश्यकता है। यह सही नहीं है क्योंकि यह थ्रेड-सुरक्षित नहीं है और आपको कॉल करने के लिए कौन सा फ़ंक्शन प्रदान करने के लिए नियंत्रण नहीं देता है। क्या होगा यदि आपके पास एकाधिक Threads
हैं जो मुख्य धागे को सूचित करने की आवश्यकता है?
एक और समाधान जो आप देखेंगे Thread
के बजाय कोरआउट का उपयोग करना है। यह काम नहीं करता है। सॉकेट के लिए कोरआउट का उपयोग कुछ भी नहीं बदलेगा। आप अभी भी अपनी freezing समस्याओं के साथ समाप्त हो जाएंगे। आपको अपने Thread
कोड से चिपके रहना होगा या Async
का उपयोग करना होगा।
ऐसा करने के उचित तरीकों में से एक है List
जैसे संग्रह बनाना। जब आपको मुख्य थ्रेड में निष्पादित करने की आवश्यकता होती है, तो उस फ़ंक्शन को कॉल करें जो कोड को Action
में निष्पादित करने के लिए संग्रहीत करता है। कॉपी है कि एक स्थानीय Action
की List
को Action
की List
तो उस List
तो उस List
स्पष्ट में स्थानीय Action
से कोड निष्पादित। यह अन्य Threads
को निष्पादित करने के लिए प्रतीक्षा करने से रोकता है।
फ़ंक्शन को सूचित करने के लिए आपको volatile boolean
जोड़ने की भी आवश्यकता है कि List
निष्पादित करने के लिए कोड प्रतीक्षा कर रहा है।List
को स्थानीय List
पर प्रतिलिपि करते समय, इसे lock
कीवर्ड के चारों ओर लपेटने के लिए इसे किसी अन्य थ्रेड को लिखने से रोकने के लिए लपेटा जाना चाहिए।
एक स्क्रिप्ट करता है कि क्या मैं उपर्युक्त:
UnityThread
स्क्रिप्ट:
#define ENABLE_UPDATE_FUNCTION_CALLBACK
#define ENABLE_LATEUPDATE_FUNCTION_CALLBACK
#define ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK
using System;
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
public class UnityThread : MonoBehaviour
{
//our (singleton) instance
private static UnityThread instance = null;
////////////////////////////////////////////////UPDATE IMPL////////////////////////////////////////////////////////
//Holds actions received from another Thread. Will be coped to actionCopiedQueueUpdateFunc then executed from there
private static List<System.Action> actionQueuesUpdateFunc = new List<Action>();
//holds Actions copied from actionQueuesUpdateFunc to be executed
List<System.Action> actionCopiedQueueUpdateFunc = new List<System.Action>();
// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
private volatile static bool noActionQueueToExecuteUpdateFunc = true;
////////////////////////////////////////////////LATEUPDATE IMPL////////////////////////////////////////////////////////
//Holds actions received from another Thread. Will be coped to actionCopiedQueueLateUpdateFunc then executed from there
private static List<System.Action> actionQueuesLateUpdateFunc = new List<Action>();
//holds Actions copied from actionQueuesLateUpdateFunc to be executed
List<System.Action> actionCopiedQueueLateUpdateFunc = new List<System.Action>();
// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
private volatile static bool noActionQueueToExecuteLateUpdateFunc = true;
////////////////////////////////////////////////FIXEDUPDATE IMPL////////////////////////////////////////////////////////
//Holds actions received from another Thread. Will be coped to actionCopiedQueueFixedUpdateFunc then executed from there
private static List<System.Action> actionQueuesFixedUpdateFunc = new List<Action>();
//holds Actions copied from actionQueuesFixedUpdateFunc to be executed
List<System.Action> actionCopiedQueueFixedUpdateFunc = new List<System.Action>();
// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
private volatile static bool noActionQueueToExecuteFixedUpdateFunc = true;
//Used to initialize UnityThread. Call once before any function here
public static void initUnityThread(bool visible = false)
{
if (instance != null)
{
return;
}
if (Application.isPlaying)
{
// add an invisible game object to the scene
GameObject obj = new GameObject("MainThreadExecuter");
if (!visible)
{
obj.hideFlags = HideFlags.HideAndDontSave;
}
DontDestroyOnLoad(obj);
instance = obj.AddComponent<UnityThread>();
}
}
public void Awake()
{
DontDestroyOnLoad(gameObject);
}
//////////////////////////////////////////////COROUTINE IMPL//////////////////////////////////////////////////////
#if (ENABLE_UPDATE_FUNCTION_CALLBACK)
public static void executeCoroutine(IEnumerator action)
{
if (instance != null)
{
executeInUpdate(() => instance.StartCoroutine(action));
}
}
////////////////////////////////////////////UPDATE IMPL////////////////////////////////////////////////////
public static void executeInUpdate(System.Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
lock (actionQueuesUpdateFunc)
{
actionQueuesUpdateFunc.Add(action);
noActionQueueToExecuteUpdateFunc = false;
}
}
public void Update()
{
if (noActionQueueToExecuteUpdateFunc)
{
return;
}
//Clear the old actions from the actionCopiedQueueUpdateFunc queue
actionCopiedQueueUpdateFunc.Clear();
lock (actionQueuesUpdateFunc)
{
//Copy actionQueuesUpdateFunc to the actionCopiedQueueUpdateFunc variable
actionCopiedQueueUpdateFunc.AddRange(actionQueuesUpdateFunc);
//Now clear the actionQueuesUpdateFunc since we've done copying it
actionQueuesUpdateFunc.Clear();
noActionQueueToExecuteUpdateFunc = true;
}
// Loop and execute the functions from the actionCopiedQueueUpdateFunc
for (int i = 0; i < actionCopiedQueueUpdateFunc.Count; i++)
{
actionCopiedQueueUpdateFunc[i].Invoke();
}
}
#endif
////////////////////////////////////////////LATEUPDATE IMPL////////////////////////////////////////////////////
#if (ENABLE_LATEUPDATE_FUNCTION_CALLBACK)
public static void executeInLateUpdate(System.Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
lock (actionQueuesLateUpdateFunc)
{
actionQueuesLateUpdateFunc.Add(action);
noActionQueueToExecuteLateUpdateFunc = false;
}
}
public void LateUpdate()
{
if (noActionQueueToExecuteLateUpdateFunc)
{
return;
}
//Clear the old actions from the actionCopiedQueueLateUpdateFunc queue
actionCopiedQueueLateUpdateFunc.Clear();
lock (actionQueuesLateUpdateFunc)
{
//Copy actionQueuesLateUpdateFunc to the actionCopiedQueueLateUpdateFunc variable
actionCopiedQueueLateUpdateFunc.AddRange(actionQueuesLateUpdateFunc);
//Now clear the actionQueuesLateUpdateFunc since we've done copying it
actionQueuesLateUpdateFunc.Clear();
noActionQueueToExecuteLateUpdateFunc = true;
}
// Loop and execute the functions from the actionCopiedQueueLateUpdateFunc
for (int i = 0; i < actionCopiedQueueLateUpdateFunc.Count; i++)
{
actionCopiedQueueLateUpdateFunc[i].Invoke();
}
}
#endif
////////////////////////////////////////////FIXEDUPDATE IMPL//////////////////////////////////////////////////
#if (ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK)
public static void executeInFixedUpdate(System.Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
lock (actionQueuesFixedUpdateFunc)
{
actionQueuesFixedUpdateFunc.Add(action);
noActionQueueToExecuteFixedUpdateFunc = false;
}
}
public void FixedUpdate()
{
if (noActionQueueToExecuteFixedUpdateFunc)
{
return;
}
//Clear the old actions from the actionCopiedQueueFixedUpdateFunc queue
actionCopiedQueueFixedUpdateFunc.Clear();
lock (actionQueuesFixedUpdateFunc)
{
//Copy actionQueuesFixedUpdateFunc to the actionCopiedQueueFixedUpdateFunc variable
actionCopiedQueueFixedUpdateFunc.AddRange(actionQueuesFixedUpdateFunc);
//Now clear the actionQueuesFixedUpdateFunc since we've done copying it
actionQueuesFixedUpdateFunc.Clear();
noActionQueueToExecuteFixedUpdateFunc = true;
}
// Loop and execute the functions from the actionCopiedQueueFixedUpdateFunc
for (int i = 0; i < actionCopiedQueueFixedUpdateFunc.Count; i++)
{
actionCopiedQueueFixedUpdateFunc[i].Invoke();
}
}
#endif
public void OnDisable()
{
if (instance == this)
{
instance = null;
}
}
}
उपयोग:
इस कार्यान्वयन आप में कार्यों कॉल करने के लिए अनुमति देता है सबसे प्रयुक्त एकता कार्य: Update
, LateUpdate
ए nd FixedUpdate
फ़ंक्शंस। यह आपको मुख्य Thread
में एक कोरआउट कार्य चलाने की अनुमति देता है। इसे अन्य यूनिटी कॉलबैक फ़ंक्शंस जैसे OnPreRender
और OnPostRender
में फ़ंक्शंस कॉल करने में सक्षम होने के लिए बढ़ाया जा सकता है।
। सबसे पहले, इसे Awake()
फ़ंक्शन से प्रारंभ करें।
void Awake()
{
UnityThread.initUnityThread();
}
एक और धागा से मुख्य Thread
में एक कोड निष्पादित करें.अभियान:
UnityThread.executeInUpdate(() =>
{
transform.Rotate(new Vector3(0f, 90f, 0f));
});
यह 90 डिग्री करने के लिए वर्तमान वस्तु scipt से जुड़ा हुआ है, रोटेट किए जाएंगे। अब आप एक और Thread
में यूनिटी एपीआई (transform.Rotate
) का उपयोग कर सकते हैं।
एक और धागा से मुख्य Thread
में एक समारोह फोन करें.अभियान: 2 और # 3 नमूने Update
समारोह में कार्यान्वित
Action rot = Rotate;
UnityThread.executeInUpdate(rot);
void Rotate()
{
transform.Rotate(new Vector3(0f, 90f, 0f));
}
#।
एक और धागा से LateUpdate
समारोह में एक कोड निष्पादित करें.अभियान:
इस का उदाहरण है एक कैमरा ट्रैकिंग कोड है। जब भौतिकी सामान कर इस तरह के Rigidbody
करने के लिए बल के रूप में जोड़ने
इस का उदाहरण:
UnityThread.executeInLateUpdate(()=>
{
//Your code camera moving code
});
एक और धागा से FixedUpdate
समारोह में एक कोड निष्पादित करें.अभियान।
UnityThread.executeInFixedUpdate(()=>
{
//Your code physics code
});
।एक और धागा से मुख्य Thread
में एक coroutine समारोह शुरू करने के लिए: अंत में
UnityThread.executeCoroutine(myCoroutine());
IEnumerator myCoroutine()
{
Debug.Log("Hello");
yield return new WaitForSeconds(2f);
Debug.Log("Test");
}
, यदि आप LateUpdate
और FixedUpdate
कार्यों में कुछ भी निष्पादित करने के लिए की जरूरत नहीं है, आप नीचे दिए गए इस कोड की दोनों पंक्तियों टिप्पणी करना चाहिए:
//#define ENABLE_LATEUPDATE_FUNCTION_CALLBACK
//#define ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK
इससे प्रदर्शन में वृद्धि होगी।
हाय बिजान, सामान्य यूनिटी बनाम कोरआउटिन फ़ंक्शन में नेटवर्क फ़ंक्शन को कॉल करने के बीच कोई अंतर नहीं है। ओपी में अभी भी [फ्रीजिंग] होगा (http://stackoverflow.com/q/41207487/3785314) समस्याएं अगर थ्रेड या एसिंक का उपयोग नहीं किया जाता है। मैं इसे एक उत्तर में समझाऊंगा। – Programmer
आप यह देखने के लिए मेरा जवाब देख सकते हैं कि मैं किस बारे में बात कर रहा हूं। किसी सर्वर से कनेक्ट या प्राप्त करते समय कोरआउटिन का उपयोग करना अभी भी ऐप को फ्रीज करेगा। आप केवल कोरआउट के साथ नेटवर्क सामान का उपयोग करते हैं यदि यह एक यूनिटी एपीआई है जैसे 'डब्ल्यूडब्ल्यूडब्लू' या 'यूनिटीवेबआरक्वेट' जो कोरआउट उपज का समर्थन करता है। सी # सॉकेट नहीं करता है। आपको 'थ्रेड' या' Async 'फ़ंक्शंस जैसे' BeginAccept' और 'BeginReceive'' का उपयोग करना होगा। – Programmer
@ प्रोग्रामर यह मूल्यवान जानकारी है। धन्यवाद – Bijan