مشاركة عبر


تهيئة البطيئة

تهيئة البطيئة الكائن الخاص به إنشاء يعني هو تأجيلها حتى هو المستخدم أولاً. (لهذا الموضوع، شروط تهيئة البطيئة و إنشاء مثيل البطيئة المترادفة.) تهيئة البطيئة هو أساسا استخدام لتحسين الأداء، تجنب إهدار احتساب وتقليل متطلبات ذاكرة البرنامج. هذه هي السيناريوهات الأكثر شيوعاً:

  • إذا كان لديك أحد الكائنات التي هو الثمن لإنشاء، وقد لا باستخدام البرنامج. على سبيل المثال، افترض أن لديك في ذاكرة Customerالكائن الذي يحتوي Ordersالذي يحتوي على صفيفة قطر أيمن متوسط من خاصية Orderالكائنات، إلى يمكن تهيئة، يتطلب اتصال قاعدة بيانات. إذا كان مستخدم لا يطلب dهوplay الطلبيات أو استخدام بيانات في حساب، ثم هناك هو يمر أي سبب لاستخدام ذاكرة النظام أو حساب لإنشائه. باستخدام Lazy<Orders>التصريح Ordersكائن للتهيئة البطيئة، يمكنك تجنب wasting موارد النظام عند الكائن هو غير مستخدمة.

  • إذا كان لديك أحد الكائنات التي هو الثمن لإنشاء، وتريد تأجيل الإنشاء الخاصة به حتى بعد إتمام العمليات غير ذلك مكلفة. على سبيل المثال، افترض أن لديك برنامج يقوم بتحميل عدة مثيلات الكائن عند بدء تشغيله، ولكن بعض فقط مطلوبة فورا. You can improve the بدء التشغيل الأداء of the برنامج بواسطة deferring تهيئة of the الكائنات that are not مطلوب until the مطلوب الكائنات have been تاريخ الإنشاء.

Although you can write your own تعليمات برمجية إلى perform lazy تهيئة, we recommend that you استخدم Lazy<T> instead. Lazy<T> و its related أنواع also دعم مؤشر ترابط-safety و provide a consistent ‏‏ استثناء نشر سياسة.

The following جدول lists the أنواع that the .NET الإصدار إطار العمل 4 provides إلى تمكين lazy تهيئة في different scenarios.

Type

الوصف

Lazy<T>

A فئة برنامج التضمين that provides lazy تهيئة semantics for أي class مكتبة أو معرّفة بواسطة مستخدم نوع.

ThreadLocal<T>

Resembles Lazy<T> except that it provides lazy تهيئة semantics تشغيل a مؤشر ترابط-محلي basis. Every مؤشر ترابط has الوصول إلى its own فريد القيمة.

LazyInitializer

Provides متقدم static (Shared في Visual أساسى) وظائف for lazy تهيئة of الكائنات without the زائد عن الحد of a فئة.

أساسى Lazy تهيئة

إلى define a lazy-initialized نوع, for مثال, MyType, استخدم Lazy<MyType> (Lazy(Of MyType) في Visual أساسى), كـ shown في the following مثال. If لا تفويض هو passed في the Lazy<T> الدالة الإنشائية, the wrapped نوع هو تاريخ الإنشاء بواسطة using ActivatorCreateInstance() when the القيمة خاصية أول accessed. If the نوع does not have a الافتراضي الدالة الإنشائية, a تشغيل-الوقت ‏‏ استثناء هو تم طرح.

في the following مثال, assume that Orders هو a فئة that يحتوي على an مصفوفه من Order الكائنات retrieved من a قاعدة بيانات. A Customer كائن يحتوي على an مثيل of Orders, but depending تشغيل مستخدم الاجراءات, the بيانات من the Orders كائن might not be مطلوب.

' Initialize by using default Lazy<T> constructor. The 
'Orders array itself is not created yet.
Dim _orders As Lazy(Of Orders) = New Lazy(Of Orders)()
// Initialize by using default Lazy<T> constructor. The 
// Orders array itself is not created yet.
Lazy<Orders> _orders = new Lazy<Orders>();

You can also pass a تفويض في the Lazy<T> الدالة الإنشائية that invokes a specific الدالة الإنشائية التحميل الزائد تشغيل the wrapped نوع at creation الوقت, و perform أي غير ذلك تهيئة steps that are مطلوب, كـ shown في the following مثال.

' Initialize by invoking a specific constructor on Order 
' when Value property is accessed
Dim _orders As Lazy(Of Orders) = New Lazy(Of Orders)(Function() New Orders(100))
// Initialize by invoking a specific constructor on Order when Value
// property is accessed
Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(100));

بعد the Lazy كائن هو تاريخ الإنشاء, لا مثيل of Orders هو تاريخ الإنشاء until the Value خاصية of the Lazy متغير هو accessed for the أول الوقت. تشغيل أول الوصول, the wrapped نوع هو تاريخ الإنشاء و returned, و stored for أي future الوصول.

' We need to create the array only if _displayOrders is true
If _displayOrders = True Then
    DisplayOrders(_orders.Value.OrderData)
Else
    ' Don't waste resources getting order data.
End If
// We need to create the array only if displayOrders is true
if (displayOrders == true)
{
    DisplayOrders(_orders.Value.OrderData);
}
else
{
    // Don't waste resources getting order data.
}

A Lazy<T> كائن دوماً إرجاع the same كائن أو القيمة that it was initialized مع. Therefore, the Value خاصية هو read-فقط. If Value stores a مرجع نوع, you cannot تعيين a جديد كائن إلى it. (However, you can تغيير the القيمة of its settable public حقول و خصائص.) If Value stores a القيمة نوع, you cannot تعديل its القيمة. Nevertheless, you can إنشاء a جديد متغير بواسطة invoking the متغير الدالة الإنشائية again بواسطة using جديد الوسيطات.

_orders = New Lazy(Of Orders)(Function() New Orders(10))
_orders = new Lazy<Orders>(() => new Orders(10));

The جديد lazy مثيل, مثل the earlier واحد, does not instantiate Orders until its Value خاصية أول accessed.

مؤشر ترابط-آمن تهيئة

بعض Lazy<T>التحميلات الزائدة الدالة الإنشائية تحتوي معلمة منطقية باسم isThreadSafeالتي هو المستخدمة لتحديد ما إذا كان Valueسيتم الوصول إلى خاصية من مؤشرات ترابط متعددة. إذا كنت تريد الوصول إلى خاصية من مؤشر ترابط واحد فقط، بتمرير في falseللحصول على المعتدلة الأداء فائدة. إذا كنت تريد الوصول إلى خاصية من مضاعفات عمليات جزئية، تمرير في trueلإرشاد المثيل البطيئة معالجتها بشكل صحيح لحالات السباق الذي يطرح مؤشر ترابط واحد إستثناء في تهيئة الوقت. إذا كنت استخدم على الدالة الإنشائية تحتوي isThreadSafeمعلمة، وقيمة افتراضية إلى true.

في وحدات سيناريو متعددة عمليات جزئية، مؤشر ترابط أول الوصول إلى Valueتهيئة خاصية هذا لالجميع الوصول التالية تشغيل الجميع عمليات جزئية، و الجميع عمليات جزئية بمشاركة نفس بيانات. لذلك، يهم initializes مؤشر ترابط الذي لا كائن، وهي benign حالات السباق. حالة مؤشر ترابط أول يهيّئ Valueإلى حدوث استثناء أن تم طرح، سيتم استثناء نفس تم طرح لكافة الوصول التالية من Value. هو لا يمكن لمؤشر ترابط واحد ب raهوe استثناء والآخر يهيّئ الكائن. يلي مثال توضح أن نفس Lazy<int>مثيل له نفس القيمة لثلاثة مؤشرات ترابط منفصلة.

' Initialize the integer to the managed thread id of the 
' first thread that accesses the Value property.
Dim number As Lazy(Of Integer) = New Lazy(Of Integer)(Function()
                                                          Return Thread.CurrentThread.ManagedThreadId
                                                      End Function)

Dim t1 As New Thread(Sub()
                         Console.WriteLine("number on t1 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t1.Start()

Dim t2 As New Thread(Sub()
                         Console.WriteLine("number on t2 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t2.Start()

Dim t3 As New Thread(Sub()
                         Console.WriteLine("number on t3 = {0} threadID = {1}",
                                           number.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t3.Start()

' Ensure that thread IDs are not recycled if the 
' first thread completes before the last one starts.
t1.Join()
t2.Join()
t3.Join()

' Sample Output:
'       number on t1 = 11 ThreadID = 11
'       number on t3 = 11 ThreadID = 13
'       number on t2 = 11 ThreadID = 12
'       Press any key to exit.
// Initialize the integer to the managed thread id of the 
// first thread that accesses the Value property.
Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId);

Thread t1 = new Thread(() => Console.WriteLine("number on t1 = {0} ThreadID = {1}",
                                        number.Value, Thread.CurrentThread.ManagedThreadId));
t1.Start();

Thread t2 = new Thread(() => Console.WriteLine("number on t2 = {0} ThreadID = {1}",
                                        number.Value, Thread.CurrentThread.ManagedThreadId));
t2.Start();

Thread t3 = new Thread(() => Console.WriteLine("number on t3 = {0} ThreadID = {1}", number.Value,
                                        Thread.CurrentThread.ManagedThreadId));
t3.Start();

// Ensure that thread IDs are not recycled if the 
// first thread completes before the last one starts.
t1.Join();
t2.Join();
t3.Join();

/* Sample Output:
    number on t1 = 11 ThreadID = 11
    number on t3 = 11 ThreadID = 13
    number on t2 = 11 ThreadID = 12
    Press any key to exit.
*/

إذا طلبت بيانات منفصل تشغيل كل مؤشر ترابط، استخدم ThreadLocal<T>، نوع كـ الموضحة لاحقاً في هذا الموضوع.

تطبيق خاصية مهيأ البطيئة

إلى تطبيق خاصية عامة باستخدام تهيئة البطيئة، قم بتحديد حقل النسخ الخاصية ك Lazy<T>، والعودة Valueالخاصية من getأسلوب استرجاع قيمة للخاصية.

Class Customer
    Private _orders As Lazy(Of Orders)
    Public Shared CustomerID As String
    Public Sub New(ByVal id As String)
        CustomerID = id
        _orders = New Lazy(Of Orders)(Function()
                                          ' You can specify additional 
                                          ' initialization steps here
                                          Return New Orders(CustomerID)
                                      End Function)

    End Sub
    Public ReadOnly Property MyOrders As Orders

        Get
            Return _orders.Value
        End Get

    End Property

End Class
class Customer
{
    private Lazy<Orders> _orders;
    public string CustomerID {get; private set;}
    public Customer(string id)
    {
        CustomerID = id;
        _orders = new Lazy<Orders>(() =>
        {
            // You can specify any additonal 
            // initialization steps here.
            return new Orders(this.CustomerID);
        });
    }

    public Orders MyOrders
    {
        get
        {
            // Orders is created on first access here.
            return _orders.Value;
        }
    }
}

Valueالخاصية هو القراءة-فقط؛ ولذلك، ليس له خاصية الذي يستهدف به setأسلوب استرجاع قيمة. إذا تطلب الأمر خاصية القراءة والكتابة، setيجب استدعاء أسلوب استرجاع قيمة construcإلىr النسخ لحقل إلى إنشاء جديد Lazy<T>الكائن. ومع ذلك، إذا قمت بذلك، ثم الذي يليه الوصول من Valueسيؤدي خاصية الكائن الجديد الملتفة إلى يمكن تهيئة، وقد ينخفض أداء. مؤشر ترابط-أمان قد تتأثر أيضا لأنه ليس لدى الجميع عمليات جزئية بنفس طريقة عرض بيانات. ولذلك، في وحدات سيناريو متعددة مؤشرات الترابط، إذا كنت تعرض setملحق تشغيل خصائص تهيئة البطيئة، التنسيق الإضافية قد يكون مطلوباً.

الاستثناءات في الكائنات البطيئة

كما ذكر سابقا، Lazy<T>الكائن دوماً بإرجاع نفس الكائن أو القيمة التي تمت تهيئته باستخدام، ولذلك، Valueالخاصية هو القراءة فقط. If Value stores a مرجع نوع, you cannot تعيين a جديد كائن إلى it. (However, you can تغيير the القيمة of its settable public حقول و خصائص.) If Value stores a القيمة نوع, you cannot تعديل its القيمة. هذا immutability أيضا بتوسيع إلى سلوك ‏‏ استثناء. إذا كان كائن تهيئة البطيئة يطرح إستثناء من منطق التهيئة عند Valueالوصول إلى خاصية أولاً، هذا نفسه هو استثناء تشغيل كل محاولة لاحقة للوصول إلى Valueالخاصية. الدالة الإنشائية النوع الملتفة بمعنى آخر، هو لا re-invoked، حتى في وحدات سيناريو متعددة مؤشرات الترابط. ولذلك، لا يمكن طرح متغير البطيئة إستثناء على واحد الوصول إليه وقم بإرجاع القيمة الوصول تالية.

ملاحظةملاحظة

إذا لك إنشاء Lazy<T>يحتوي IsThreadSafeوسيطة الدالة الإنشائية معينة إلى false (Falseفي Visual أساسى) ، ثم الوصول إلى الكائن من مؤشرات ترابط متعددة، قد مؤشر ترابط واحد برفع استثناء وقد ترى مؤشر ترابط آخر القيمة قابلة للاستخدام.ولذلك، عين true(Truein Vهوual أساسى) ل IsThreadSafeإذا كان هناك هو أي chance أن مؤشرات ترابط متعددة قد محاولة الوصول إلى الكائن البطيئة في نفس الوقت.

مؤشر ترابط-محلي تهيئة البطيئة

في بعض السيناريوهات ذات مؤشرات ترابط متعددة، قد تحتاج إلى إعطاء كل مؤشر ترابط بياناته الخاصة. هذه البيانات هو تسمى بيانات مؤشر ترابط المحلية . في إطار عمل.NET الإصدار 3.5 والإصدارات السابقة، ربما تقوم بتطبيق ThreadStaticسمة إلى متغير ثابتة إلى جعله مؤشر ترابط-المحلية. ومع ذلك، باستخدام ThreadStaticالسمات التي يمكن أن يؤدي إلى أخطاء دقيق. تشغيل سبيل المثال، سيؤدي العبارات أساسى حتى تهيئة المتغير إلى لتكون مهيئة فقط تشغيل مؤشر ترابط أول الذي يصل إليه، كما هو موضح في المثال التالي.

<ThreadStatic()>
Shared counter As Integer
[ThreadStatic]
static int counter = 1;

تشغيل الجميع غير ذلك سيتم تهيئة عمليات جزئية، المتغير باستخدام القيمة افتراضية (صفر). كبديل في الإصدار الرابع من برنامج.NET Framework، يمكنك استخدام System.Threading.ThreadLocal<T>الكتابة لإنشاء متغير مؤشر ترابط المحلية والمستندة إلى مثيل هو تهيئة تشغيل الجميع عمليات جزئية Action<T>المفوض التي توفرها. في المثال التالي، الجميع مؤشرات ترابط هذا الوصول counterسيري قيمتها البداية كـ 1.

Dim betterCounter As ThreadLocal(Of Integer) = New ThreadLocal(Of Integer)(Function() 1)
ThreadLocal<int> betterCounter = new ThreadLocal<int>(() => 1);

ThreadLocal<T>التفاف الكائن الخاص به في كثير نفس الطريقةLazy<T>، مع هذه الاختلافات الأساسية:

  • كل مؤشر ترابط تهيئة متغير محلي مؤشر الترابط باستخدام بياناتها الخاصة التي هو لا يمكن الوصول إليها من عمليات جزئية الأخرى.

  • ThreadLocal<T>.Valueخاصية القراءة والكتابة، ويمكن ‏‏تاريخ التعديل أي عدد من المرات. قد يؤثر ذلك على نشر ‏‏ استثناء، ل مثال، واحد getتشغيل أن تقوم بإصدار استثناء ولكن يمكن بنجاح يهيّئ التالي القيمة.

  • في حالة عدم وجود المفوض اليهيّئ هو المتوفرة، ThreadLocal<T>سيتم يهيّئ نوعه الملتفة باستخدام القيمة افتراضية للنوع. في ترتيب هو اعتبار ThreadLocal<T>هو consهوtent مع ThreadStaticAttributeالسمة.

يلي مثال يوضح التي كل مؤشر ترابط الذي يصل إلى ThreadLocal<int>يحصل المثيل الخاص به نسخ فريدة من بيانات.

' Initialize the integer to the managed thread id on a per-thread basis.
Dim threadLocalNumber As New ThreadLocal(Of Integer)(Function() Thread.CurrentThread.ManagedThreadId)
Dim t4 As New Thread(Sub()
                         Console.WriteLine("number on t4 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t4.Start()

Dim t5 As New Thread(Sub()
                         Console.WriteLine("number on t5 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t5.Start()

Dim t6 As New Thread(Sub()
                         Console.WriteLine("number on t6 = {0} threadID = {1}",
                                           threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)
                     End Sub)
t6.Start()

' Ensure that thread IDs are not recycled if the 
' first thread completes before the last one starts.
t4.Join()
t5.Join()
t6.Join()

'Sample(Output)
'      threadLocalNumber on t4 = 14 ThreadID = 14 
'      threadLocalNumber on t5 = 15 ThreadID = 15
'      threadLocalNumber on t6 = 16 ThreadID = 16 
// Initialize the integer to the managed thread id on a per-thread basis.
ThreadLocal<int> threadLocalNumber = new ThreadLocal<int>(() => Thread.CurrentThread.ManagedThreadId);
Thread t4 = new Thread(() => Console.WriteLine("threadLocalNumber on t4 = {0} ThreadID = {1}",
                                    threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId));
t4.Start();

Thread t5 = new Thread(() => Console.WriteLine("threadLocalNumber on t5 = {0} ThreadID = {1}",
                                    threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId));
t5.Start();

Thread t6 = new Thread(() => Console.WriteLine("threadLocalNumber on t6 = {0} ThreadID = {1}",
                                    threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId));
t6.Start();

// Ensure that thread IDs are not recycled if the 
// first thread completes before the last one starts.
t4.Join();
t5.Join();
t6.Join();

/* Sample Output:
   threadLocalNumber on t4 = 14 ThreadID = 14 
   threadLocalNumber on t5 = 15 ThreadID = 15
   threadLocalNumber on t6 = 16 ThreadID = 16 
*/

مؤشر ترابط-محلي متغيرات في متوازى.For و ForEach

عندما تقوم باستخدام ParallelFor()أسلوب أو ParallelForEach()أسلوب إلى يكرر عبر المصادر بيانات في نفس الوقت، يمكنك استخدام التحميلات الزائدة التي تحتوي على دعم مضمن للبيانات المحلية مؤشر الترابط. في هذه الطرق، ومؤشر ترابط-المجتمع المحلي هو إنجاز باستخدام التفويضات المحلية لإنشاء، والوصول، وتنظيف بيانات. للمزيد من المعلومات، راجع كيفية: كتابة حلقة Parallel.For مع المتغيرات المحلية مؤشر الترابط وHow to: Write a Parallel.ForEach Loop That Has Thread-Local Variables.

استخدام تهيئة البطيئة لوحدات سيناريو منخفض-جهاز عرض

In scenarios where you have إلى lazy-يهيّئ a large رقم of الكائنات, you might decide that التفاف each كائن in a Lazy<T> requires too much memory أو too many computing موارد. أو، قد يكون لديك متطلبات صارمة حول تهيئة البطيئة كيف هو المعروضة. في مثل هذه الحالات، يمكنك استخدام الأساليب static(Sharedin Visual أساسى) الخاصة System.Threading.LazyInitializerالفئة إلى البطيئة يهيّئ كل كائن بدون التفاف في مثيل Lazy<T>.

في المثال التالي، تفترض، بدلاً من الالتفاف بأكمله Ordersكائن في واحد Lazy<T>كائن، لديك البطيئة تهيئة الفرد Orderكائن s فقط إذا كانت مطلوبة.

' Assume that _orders contains null values, and
' we only need to initialize them if displayOrderInfo is true
If displayOrderInfo = True Then


    For i As Integer = 0 To _orders.Length
        ' Lazily initialize the orders without wrapping them in a Lazy(Of T)
        LazyInitializer.EnsureInitialized(_orders(i), Function()
                                                          ' Returns the value that will be placed in the ref parameter.
                                                          Return GetOrderForIndex(i)
                                                      End Function)
    Next
End If
// Assume that _orders contains null values, and
// we only need to initialize them if displayOrderInfo is true
if(displayOrderInfo == true)
{
    for (int i = 0; i < _orders.Length; i++)
    {
        // Lazily initialize the orders without wrapping them in a Lazy<T>
        LazyInitializer.EnsureInitialized(ref _orders[i], () =>
            {
                // Returns the value that will be placed in the ref parameter.
                return GetOrderForIndex(i);
            });
    }
}

في ترتيب هو المثال، لاحظ أنه عملية تهيئة هو استدعاء تشغيل كل تكرار من الحلقة. في وحدات سيناريو متعددة عمليات جزئية، مؤشر ترابط أول إلى تهيئة استدعاء إجراء هو يراها قيمته على الجميع عمليات جزئية. عمليات جزئية لاحق أيضا باستدعاء إجراء تهيئة، ولكن لا يتم استخدام نتائجها. إذا كان ترتيب هو نوع حالة تعارض محتمل هو غير مقبولة، استخدام التحميل الزائد من EnsureInitializedالتي تأخذ إحدى الوسائط منطقية وكائن المزامنة.

راجع أيضًا:

المهام

كيفية القيام بما يلي: قم بإجراء تهيئة البطيئة للكائنات

المبادئ

عمليات جزئية و مؤشر الترابط التشعبي

نظرة عامة مكتبة Parallel المهمة

موارد أخرى

مدارة مؤشر الترابط التشعبي أساسيات