Yavaş Başlatma

Bir nesnenin yavaş başlatılması , oluşturma işleminin ilk kullanılana kadar ertelenmesi anlamına gelir. (Bu konu için, yavaş başlatma ve yavaş örnekleme terimleri eş anlamlıdır.) Yavaş başlatma öncelikli olarak performansı geliştirmek, gereksiz hesaplamaları önlemek ve program belleği gereksinimlerini azaltmak için kullanılır. En yaygın senaryolar şunlardır:

  • Oluşturulması pahalı bir nesneniz varsa ve program bunu kullanmayabilir. Örneğin, bellekteCustomer, başlatılması için veritabanı bağlantısı gerektiren büyük bir nesne dizisi Order içeren bir özelliğe sahip Orders bir nesneniz olduğunu varsayalım. Kullanıcı hiçbir zaman Siparişleri görüntülemeyi veya verileri hesaplamada kullanmayı sormazsa, sistem belleğini veya bilgi işlem döngülerini kullanarak oluşturmak için bir neden yoktur. Lazy<Orders> kullanarak nesnesini yavaş başlatma için bildirerekOrders, nesne kullanılmadığında sistem kaynaklarının israfını önleyebilirsiniz.

  • Oluşturulması pahalı bir nesneniz olduğunda ve diğer pahalı işlemler tamamlanana kadar oluşturulmasını ertelemek istediğinizde. Örneğin, programınızın başlatıldığında birkaç nesne örneği yüklediğini, ancak yalnızca bazılarının hemen gerekli olduğunu varsayalım. Gerekli nesneler oluşturulana kadar gerekli olmayan nesnelerin başlatılmasını erteleyerek programın başlangıç performansını geliştirebilirsiniz.

Yavaş başlatma gerçekleştirmek için kendi kodunuzu yazabilirsiniz, ancak bunun yerine kullanmanızı Lazy<T> öneririz. Lazy<T> ve ilgili türleri de iş parçacığı güvenliğini destekler ve tutarlı bir özel durum yayma ilkesi sağlar.

Aşağıdaki tabloda, .NET Framework sürüm 4'ün farklı senaryolarda yavaş başlatmayı etkinleştirmek için sağladığı türler listelenmektedir.

Type Açıklama
Lazy<T> Herhangi bir sınıf kitaplığı veya kullanıcı tanımlı tür için gecikmeli başlatma semantiği sağlayan sarmalayıcı sınıfı.
ThreadLocal<T> Lazy<T> İş parçacığı yerel temelinde gecikmeli başlatma semantiği sağlaması dışında benzer. Her iş parçacığının kendi benzersiz değerine erişimi vardır.
LazyInitializer Bir sınıfın yükü olmadan nesnelerin yavaş başlatılması için gelişmiş static (Shared Visual Basic'te) yöntemler sağlar.

Temel Gecikmeli Başlatma

Yavaş başlatılan bir tür tanımlamak için, aşağıdaki MyTypeörnekte gösterildiği gibi (Lazy(Of MyType) Visual Basic'te) kullanın Lazy<MyType> . Oluşturucuda Lazy<T> hiçbir temsilci geçirilmemişse, değer özelliğine ilk kez erişildiğinde kullanılarak Activator.CreateInstance sarmalanan tür oluşturulur. Türün parametresiz oluşturucusu yoksa, bir çalışma zamanı özel durumu oluşturulur.

Aşağıdaki örnekte, bir veritabanından alınan bir nesne dizisi Order içeren bir sınıf olduğunu Orders varsayalım. Nesne Customer bir örneğini Ordersiçerir, ancak kullanıcı eylemlerine bağlı olarak nesneden Orders alınan veriler gerekli olmayabilir.

// Initialize by using default Lazy<T> constructor. The
// Orders array itself is not created yet.
Lazy<Orders> _orders = new Lazy<Orders>();
' 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)()

Ayrıca oluşturucuda Lazy<T> oluşturma zamanında sarmalanan tür üzerinde belirli bir oluşturucu aşırı yüklemesini çağıran bir temsilci geçirebilir ve aşağıdaki örnekte gösterildiği gibi gerekli olan diğer başlatma adımlarını gerçekleştirebilirsiniz.

// Initialize by invoking a specific constructor on Order when Value
// property is accessed
Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(100));
' 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))

Lazy nesnesi oluşturulduktan sonra, Lazy değişkeninin özelliğine Value ilk kez erişilene kadar örneği Orders oluşturulmaz. İlk erişimde sarmalanan tür oluşturulur ve döndürülür ve gelecekteki tüm erişimler için depolanır.

// 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.
}
' 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

Bir Lazy<T> nesne her zaman ile başlatıldığı aynı nesneyi veya değeri döndürür. Bu nedenle özelliği Value salt okunurdur. Value Bir başvuru türü depolarsa, ona yeni bir nesne atayamazsınız. (Ancak, ayarlanabilir ortak alanlarının ve özelliklerinin değerini değiştirebilirsiniz.) Value Bir değer türünü depolarsa, değerini değiştiremezsiniz. Bununla birlikte, yeni bağımsız değişkenler kullanarak değişken oluşturucuyu yeniden çağırarak yeni bir değişken oluşturabilirsiniz.

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

Önceki örnek gibi yeni gecikmeli örnek, özelliğine Value ilk erişilene Orders kadar örnek oluşturmaz.

İş Parçacığı Kasa Başlatma

Varsayılan olarak, Lazy<T> nesneler iş parçacığı açısından güvenlidir. Başka bir ifadeyle, oluşturucu iş parçacığı güvenliği türünü belirtmezse, Lazy<T> oluşturduğu nesneler iş parçacığı açısından güvenlidir. Çok iş parçacıklı senaryolarda, iş parçacığı güvenli Lazy<T> bir nesnenin özelliğine erişen Value ilk iş parçacığı, bunu tüm iş parçacıklarında sonraki tüm erişimler için başlatır ve tüm iş parçacıkları aynı verileri paylaşır. Bu nedenle, nesneyi hangi iş parçacığının başlatdığı önemli değildir ve yarış koşulları zararsızdır.

Not

Özel durum önbelleğe alma özelliğini kullanarak bu tutarlılığı hata koşullarına genişletebilirsiniz. Daha fazla bilgi için bir sonraki bölüm olan Gecikmeli Nesnelerdeki Özel Durumlar bölümüne bakın.

Aşağıdaki örnekte, aynı Lazy<int> örneğin üç ayrı iş parçacığı için aynı değere sahip olduğu gösterilmektedir.

// 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.
*/
' 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.

Her iş parçacığında ayrı verilere ihtiyacınız varsa, bu konunun ilerleyen bölümlerinde açıklandığı gibi türünü kullanın ThreadLocal<T> .

Bazı Lazy<T> oluşturucuların özelliğine birden çok iş parçacığından erişilip erişilmeyeceğini Value belirtmek için kullanılan adlı isThreadSafe bir Boole parametresi vardır. Özelliğe yalnızca bir iş parçacığından erişmeyi planlıyorsanız, mütevazı false bir performans avantajı elde etmek için geçiş yapın. Özelliğine birden çok iş parçacığından erişmeyi planlıyorsanız, örneği bir iş parçacığının Lazy<T> başlatma zamanında özel durum oluşturacak yarış koşullarını doğru şekilde işlemesini bildirmek için geçirintrue.

Bazı Lazy<T> oluşturucuların adlı modebir LazyThreadSafetyMode parametresi vardır. Bu oluşturucular ek iş parçacığı güvenliği modu sağlar. Aşağıdaki tabloda, bir Lazy<T> nesnenin iş parçacığı güvenliğinin, iş parçacığı güvenliğini belirten oluşturucu parametrelerinden nasıl etkilendiği gösterilmektedir. Her oluşturucu en fazla bir parametreye sahiptir.

Nesnenin iş parçacığı güvenliği LazyThreadSafetyModemode Parametre Boole isThreadSafe parametresi İş parçacığı güvenlik parametresi yok
Tamamen iş parçacığı güvenli; bir kerede yalnızca bir iş parçacığı değeri başlatmaya çalışır. ExecutionAndPublication true Evet.
İş parçacığı güvenli değil. None false Uygulanamaz.
Tamamen iş parçacığı güvenli; threads değeri başlatmak için yarışıyor. PublicationOnly Uygulanamaz. Uygulanamaz.

Tabloda gösterildiği gibi, parametresini mode belirtmekLazyThreadSafetyMode.ExecutionAndPublication, parametresini isThreadSafe belirtmekle true aynıdır ve belirtmek LazyThreadSafetyMode.None de ile falseaynıdır.

Ne Execution olduğu ve Publication nelere başvuracakları hakkında daha fazla bilgi için bkz LazyThreadSafetyMode. .

Belirtilmesi LazyThreadSafetyMode.PublicationOnly , birden çok iş parçacığının örneği başlatmayı denemesine Lazy<T> olanak tanır. Bu yarışı yalnızca bir iş parçacığı kazanabilir ve diğer tüm iş parçacıkları başarılı iş parçacığı tarafından başlatılan değeri alır. Başlatma sırasında bir iş parçacığında özel durum oluşursa, bu iş parçacığı başarılı iş parçacığı tarafından ayarlanan değeri almaz. Özel durumlar önbelleğe alınmaz, bu nedenle özelliğe daha sonra erişim Value girişimi başarılı bir şekilde başlatılabilir. Bu, aşağıdaki bölümde açıklanan özel durumların diğer modlarda ele alınma biçiminden farklıdır. Daha fazla bilgi için numaralandırmaya LazyThreadSafetyMode bakın.

Gecikmeli Nesnelerdeki Özel Durumlar

Daha önce belirtildiği gibi, bir Lazy<T> nesne her zaman ile başlatıldığı nesne veya değeri döndürür ve bu nedenle Value özelliği salt okunurdur. Özel durum önbelleğe almayı etkinleştirirseniz, bu değişmezlik özel durum davranışına da genişletir. Yavaş başlatılan bir nesnede özel durum önbelleğe alma etkinse ve özelliğe ilk erişildiğinde Value başlatma yönteminden bir özel durum oluşturursa, özelliğe erişmek Value için sonraki her girişimde aynı özel durum oluşturulur. Başka bir deyişle, sarmalanan türün oluşturucusu, çok iş parçacıklı senaryolarda bile hiçbir zaman yeniden çağrılır. Bu nedenle, Lazy<T> nesnesi bir erişimde özel durum oluşturamaz ve sonraki erişimde bir değer döndüremez.

Özel durum önbelleğe alma, bir başlatma yöntemi (valueFactoryparametre) alan herhangi System.Lazy<T> bir oluşturucu kullandığınızda etkinleştirilir; örneğin, oluşturucuyu kullandığınızda Lazy(T)(Func(T))etkinleştirilir. Oluşturucu da bir LazyThreadSafetyMode değer (mode parametre) alıyorsa, veya belirtin.LazyThreadSafetyMode.NoneLazyThreadSafetyMode.ExecutionAndPublication Bir başlatma yöntemi belirtmek, bu iki mod için özel durum önbelleğe almayı etkinleştirir. Başlatma yöntemi çok basit olabilir. Örneğin, C# dilinde veya New Lazy(Of Contents)(Function() New Contents()) Visual Basic'te için Tnew Lazy<Contents>(() => new Contents(), mode) parametresiz oluşturucuyu çağırabilir. Başlatma yöntemi belirtmeyen bir System.Lazy<T> oluşturucu kullanırsanız, parametresiz T oluşturucu tarafından oluşan özel durumlar önbelleğe alınmaz. Daha fazla bilgi için numaralandırmaya LazyThreadSafetyMode bakın.

Not

Oluşturucu parametresi veya oluşturucu parametresi olarak ayarlanmış falseLazyThreadSafetyMode.Nonemode bir Lazy<T> nesne isThreadSafe oluşturursanız, nesneye Lazy<T> tek bir iş parçacığından erişmeniz veya kendi eşitlemenizi sağlamanız gerekir. Bu, özel durum önbelleğe alma da dahil olmak üzere nesnenin tüm yönleri için geçerlidir.

Önceki bölümde belirtildiği gibi, Lazy<T> özel durumları farklı şekilde ele alarak LazyThreadSafetyMode.PublicationOnly oluşturulan nesneler. ile PublicationOnly, örneği başlatmak Lazy<T> için birden çok iş parçacığı rekabet edebilir. Bu durumda, özel durumlar önbelleğe alınmaz ve özelliğine erişme Value girişimleri başlatma başarılı olana kadar devam edebilir.

Aşağıdaki tabloda, oluşturucuların özel durum önbelleğe almayı denetleme şekli Lazy<T> özetlemektedir.

Oluşturucu İş parçacığı güvenlik modu Başlatma yöntemini kullanır Özel durumlar önbelleğe alınır
Lazy(T)() (ExecutionAndPublication) Hayır Hayır
Lazy(T)(Func(T)) (ExecutionAndPublication) Yes Yes
Lazy(T)(Boole) True (ExecutionAndPublication) veya false (None) Hayır Hayır
Lazy(T)(Func(T), Boole) True (ExecutionAndPublication) veya false (None) Yes Yes
Lazy(T)(LazyThread Kasa tyMode) Kullanıcı tarafından belirtilen Hayır Hayır
Lazy(T)(Func(T), LazyThread Kasa tyMode) Kullanıcı tarafından belirtilen Yes Kullanıcı belirtirse PublicationOnlyhayır; aksi takdirde evet.

Gecikmeli Başlatılan Özellik Uygulama

Gecikmeli başlatma kullanarak bir ortak özellik uygulamak için özelliğinin yedekleme alanını olarak Lazy<T>tanımlayın ve özelliğin erişimcisinden get özelliğini döndürinValue.

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 additional
            // initialization steps here.
            return new Orders(this.CustomerID);
        });
    }

    public Orders MyOrders
    {
        get
        {
            // Orders is created on first access here.
            return _orders.Value;
        }
    }
}
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

Value özelliği salt okunurdur; bu nedenle, onu kullanıma sunan özelliğin erişimcisi yokturset. Nesne tarafından Lazy<T> desteklenen bir okuma/yazma özelliğine ihtiyacınız varsa, erişimcinin set yeni Lazy<T> bir nesne oluşturması ve bunu yedekleme deposuna ataması gerekir. Erişimci, set erişimciye set geçirilen yeni özellik değerini döndüren bir lambda ifadesi oluşturmalı ve bu lambda ifadesini yeni Lazy<T> nesne için oluşturucuya geçirmelidir. Özelliğin Value bir sonraki erişimi, yeni Lazy<T>öğesinin başlatılmasına Value neden olur ve özelliği bundan sonra özelliğine atanan yeni değeri döndürür. Bu karmaşık düzenlemenin nedeni, yerleşik Lazy<T>olarak bulunan çok iş parçacıklı korumaları korumaktır. Aksi takdirde özellik erişimcilerinin özellik tarafından Value döndürülen ilk değeri önbelleğe alıp yalnızca önbelleğe alınan değeri değiştirmesi ve bunu yapmak için kendi iş parçacığı güvenli kodunuzu yazmanız gerekir. Bir nesne tarafından Lazy<T> yedeklenen bir okuma/yazma özelliğinin gerektirdiği ek başlatmalar nedeniyle, performans kabul edilebilir olmayabilir. Ayrıca, belirli senaryoya bağlı olarak, ayarlayıcılar ve alıcıların yarış koşullarını önlemek için ek koordinasyon gerekebilir.

İş Parçacığı Yerel Gecikmeli Başlatma

Çok iş parçacıklı bazı senaryolarda her iş parçacığına kendi özel verilerini vermek isteyebilirsiniz. Bu tür veriler iş parçacığı yerel verileri olarak adlandırılır. .NET Framework sürüm 3.5 ve önceki sürümlerinde özniteliğini bir statik değişkene uygulayarak ThreadStatic iş parçacığını yerel hale getirebilirsiniz. Ancak özniteliğini ThreadStatic kullanmak küçük hatalara yol açabilir. Örneğin, temel başlatma deyimleri bile değişkenin aşağıdaki örnekte gösterildiği gibi yalnızca ona erişen ilk iş parçacığında başlatılmasına neden olur.

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

Diğer tüm iş parçacıklarında, değişken varsayılan değeri (sıfır) kullanılarak başlatılır. .NET Framework sürüm 4'te alternatif olarak, sağladığınız temsilci tarafından Action<T> tüm iş parçacıklarında başlatılan örnek tabanlı, iş parçacığı yerel değişkeni oluşturmak için türünü kullanabilirsinizSystem.Threading.ThreadLocal<T>. Aşağıdaki örnekte, erişen counter tüm iş parçacıkları başlangıç değerini 1 olarak görür.

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

ThreadLocal<T> nesnesini ile aynı şekilde Lazy<T>sarmalar ve aşağıdaki temel farkları uygular:

  • Her iş parçacığı, diğer iş parçacıklarından erişilmeyen kendi özel verilerini kullanarak iş parçacığı yerel değişkenini başlatır.

  • ThreadLocal<T>.Value özelliği okuma-yazmadır ve istediğiniz sayıda değiştirilebilir. Bu, özel durum yayma işlemini etkileyebilir, örneğin, bir get işlem özel durum oluşturabilir, ancak bir sonraki işlem değeri başarıyla başlatabilir.

  • Başlatma temsilcisi sağlanmazsa, ThreadLocal<T> türün varsayılan değerini kullanarak sarmalanmış türünü başlatır. Bu bağlamda özniteliğiyle ThreadLocal<T>ThreadStaticAttribute tutarlıdır.

Aşağıdaki örnek, örneğe erişen her iş parçacığının ThreadLocal<int> kendi benzersiz veri kopyasını aldığını gösterir.

// 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
*/
' 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 

Parallel.For ve ForEach'te İş Parçacığı Yerel Değişkenleri

Veri kaynaklarını paralel olarak yinelemek için yöntemini veya Parallel.ForEach yöntemini kullandığınızdaParallel.For, iş parçacığı yerel verileri için yerleşik desteği olan aşırı yüklemeleri kullanabilirsiniz. Bu yöntemlerde iş parçacığı yerelliği, verileri oluşturmak, bunlara erişmek ve verileri temizlemek için yerel temsilciler kullanılarak elde edilir. Daha fazla bilgi için bkz . Nasıl yapılır: İş Parçacığı Yerel Değişkenleri ile Parallel.For Döngüsü Yazma ve Nasıl yapılır: Partition-Local Değişkenleriyle Parallel.ForEach Döngüsü Yazma.

Düşük Yük Senaryoları için Gecikmeli Başlatma Kullanma

Çok sayıda nesneyi yavaş başlatmanız gereken senaryolarda, içindeki her nesneyi Lazy<T> sarmalamanın çok fazla bellek veya çok fazla bilgi işlem kaynağı gerektirdiğine karar vekleyebilirsiniz. Alternatif olarak, gecikmeli başlatmanın nasıl kullanıma sunulduğu konusunda katı gereksinimleriniz olabilir. Böyle durumlarda, sınıfının (Shared Visual Basic'te) yöntemlerini System.Threading.LazyInitializer kullanarak static bir örneğine Lazy<T>sarmalamadan her nesneyi yavaş başlatabilirsiniz.

Aşağıdaki örnekte, bir nesnenin tamamını Orders tek Lazy<T> bir nesneye sarmalamak yerine yalnızca gerekli olduklarında yavaş başlatılan tek tek Order nesnelere sahip olduğunuzu varsayalım.

// 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);
        });
    }
}
' 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

Bu örnekte, başlatma yordamının döngünün her yinelemesinde çağrıldığına dikkat edin. Çok iş parçacıklı senaryolarda, başlatma yordamını çağıran ilk iş parçacığı, değeri tüm iş parçacıkları tarafından görülen iş parçacığıdır. Sonraki iş parçacıkları başlatma yordamını da çağırır, ancak sonuçları kullanılmaz. Bu tür bir olası yarış durumu kabul edilebilir değilse, boole bağımsız değişkeni ve eşitleme nesnesi alan öğesinin aşırı yüklemesini LazyInitializer.EnsureInitialized kullanın.

Ayrıca bkz.