Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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, bellekte
Customer
, başlatılması için veritabanı bağlantısı gerektiren büyük bir nesne dizisiOrders
içeren bir özelliğe sahipOrder
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>
kullanarakOrders
nesnesini tembel başlatma için bildirdiğinizde, 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.
Türü | 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> dışında, iş parçacığı yerel temelli gecikmeli başlatma semantiği sağlaması açısından benzer. Her iş parçacığı kendi benzersiz değerine erişebilir. |
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<MyType>
Visual Basic'te) kullanın Lazy(Of MyType)
. Eğer oluşturucuda bir Lazy<T> temsilcisi geçirilmemişse, değer özelliğine ilk kez erişildiğinde, Activator.CreateInstance kullanılarak sarmalanan tür oluşturulur. Türün parametresiz kurucusu yoksa, bir çalışma zamanı istisnası fırlatılır.
Aşağıdaki örnekte, bir veritabanından alınan bir nesne dizisi Orders
içeren bir sınıf olduğunu Order
varsayalım. Birtakım Customer
nesnesi Orders
örneğini içerir, ancak kullanıcı eylemlerine bağlı olarak, Orders
nesnesinden alınan veriler gerekli olmayabilir.
// Initialize by using default Lazy<T> constructor. The
// Orders array itself is not created yet.
Lazy<Orders> _orders = new();
' 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, `Lazy<T>` yapıcısına sarmalanan tür üzerinde belirli bir yapıcı aşırı yüklemesini çağıran bir temsilci geçirerek, gerekli diğer başlatma adımlarını gerçekleştirebilir ve bunu aşağıdaki örnekte gösterildiği şekilde yapabilirsiniz.
// Initialize by invoking a specific constructor on Order when Value
// property is accessed
Lazy<Orders> _orders = new(() => 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 Orders
ilk kez erişilene kadar örneği Value oluşturulmaz. İlk erişimde sarmalanan tür oluşturulur, geri döndürülür, ve gelecekteki erişimler için depolanır.
// We need to create the array only if displayOrders is true
if (s_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 Value özelliği 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))
Tembel bir örnek olan yeni örnek, önceki örnek gibi, Orders
özelliğine ilk kez erişilene dek örnek oluşturmaz.
İş Parçacığı Güvenli 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 Value bir nesnenin özelliğine erişen Lazy<T> 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(() => Environment.CurrentManagedThreadId);
Thread t1 = new(() => Console.WriteLine($"number on t1 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t1.Start();
Thread t2 = new(() => Console.WriteLine($"number on t2 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t2.Start();
Thread t3 = new(() => Console.WriteLine($"number on t3 = {number.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
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.
Eğer her iş parçacığı için ayrı verilere ihtiyaç duyuyorsanız, bu konunun ilerleyen bölümlerinde açıklandığı gibi ThreadLocal<T> türünü kullanın.
Bazı Lazy<T> oluşturucular, isThreadSafe
adlı bir Boole parametresi içerir, bu da Value özelliğine birden fazla iş parçacığından erişilip erişilmeyeceğini belirtmek için kullanılır. Özelliğe yalnızca bir iş parçacığından erişmeyi planlıyorsanız, mütevazı bir performans avantajı sağlamak için false
geçin. Eğer birden fazla iş parçacığından özelliğe erişmeyi planlıyorsanız, bir iş parçacığının başlatma zamanında özel durum oluşturabilecek yarış koşullarını doğru şekilde işlemesi için true
geçirerek Lazy<T> örneğine talimat verin.
Bazı Lazy<T> oluşturucuların LazyThreadSafetyMode adlı bir mode
parametresi vardır. Bu oluşturucular, ek bir iş parçacığı güvenliği seçeneği sunar. 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 |
LazyThreadSafetyMode
mode parametre |
Boole isThreadSafe parametresi |
İş parçacığı güvenliği parametreleri yok |
---|---|---|---|
Tamamen iş parçacığı açısından 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; iş parçacıkları değeri başlatmak için yarışıyor. | PublicationOnly | Uygulanamaz. | Uygulanamaz. |
Tabloda gösterildiği gibi, LazyThreadSafetyMode.ExecutionAndPublication parametresini belirtmek, mode
parametresini belirtmekle aynıdır ve true
belirlemek, isThreadSafe
belirlemekle aynıdır.
Execution
ve Publication
'in neye atıfta bulunduğu hakkında daha fazla bilgi için LazyThreadSafetyMode'ye bakın.
LazyThreadSafetyMode.PublicationOnly belirtilmesi, birden çok iş parçacığının Lazy<T> örneğini başlatmayı denemesine 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 sonraki bir erişim Value girişimi başarılı bir şekilde başlatılmasına yol açabilir. 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 İstisnalar
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. Eğer tembel başlatılan bir nesnede istisna önbelleğe alma etkinse ve Value özelliğine ilk erişildiğinde başlatma yönteminden bir istisna fırlatırsa, Value özelliğine erişme girişimlerinin her birinde aynı istisna tekrar fırlatılır. Başka bir deyişle, sarmalanan türün oluşturucusu, çok iş parçacıklı senaryolarda bile asla tekrar çağrılmaz. Bu nedenle, Lazy<T> nesnesi bir erişimde özel durum oluşturamaz ve sonraki erişimde bir değer döndüremez.
Özel durumu önbelleğe alma, başlatma yöntemi (System.Lazy<T> parametre) alan herhangi bir valueFactory
oluşturucu kullandığınızda etkinleştirilir; örneğin, Lazy(T)(Func(T))
oluşturucuyu kullandığınızda etkinleştirilir. Oluşturucu LazyThreadSafetyMode değerini (mode
parametresi) de alıyorsa, LazyThreadSafetyMode.ExecutionAndPublication veya LazyThreadSafetyMode.None belirtin. 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 T
için veya Visual Basic'te new Lazy<Contents>(() => new Contents(), mode)
parametresiz oluşturucuyu çağırabilir: New Lazy(Of Contents)(Function() New Contents())
. 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
Eğer Lazy<T> oluşturucu parametresi isThreadSafe
olarak ayarlanmış bir false
nesnesi veya mode
oluşturucu parametresi LazyThreadSafetyMode.None olarak ayarlanmış bir nesne 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> belirtilerek oluşturulan LazyThreadSafetyMode.PublicationOnly nesneleri, özel durumları farklı şekilde ele alır. PublicationOnly ile, birden çok iş parçacığı Lazy<T> örneğini başlatmak için rekabet edebilir. Bu durumda, istisnalar önbelleğe alınmaz ve Value özelliğine erişme girişimleri başlatma başarılı olana kadar devam edebilir.
Aşağıdaki tabloda, Lazy<T> oluşturucularının özel durum önbelleğe almayı denetleme şekli özetlenmektedir.
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) | Evet | Evet |
Lazy(T)(Boole) |
True (ExecutionAndPublication) veya false (None) |
Hayır | Hayır |
Lazy(T)(Func(T), Boole) |
True (ExecutionAndPublication) veya false (None) |
Evet | Evet |
Lazy(T)(LazyThreadSafetyMode) | Kullanıcı tarafından belirtilen | Hayır | Hayır |
Lazy(T)(Func(T), LazyThreadSafetyMode) | Kullanıcı tarafından belirtilen | Evet | Kullanıcı belirtirse PublicationOnlyhayır; aksi takdirde evet. |
Tembel Başlatılan Özelliğin Uygulanması
Genel bir özelliği gecikmeli başlatma kullanarak uygulamak için, özelliğin yedekleme alanını Lazy<T> olarak tanımlayın ve Value erişimcisinden get
özelliğini döndürün.
class Customer
{
private readonly 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(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 açığa çıkaran özelliğin bir erişimcisi yokturset
. Eğer Lazy<T> nesnesi tarafından desteklenen bir okuma/yazma özelliğine ihtiyacınız varsa, set
erişimcinin yeni bir Lazy<T> nesnesi oluşturması ve bunu arka depoya 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 neden olur ve bundan sonra Value özelliği, özelliğe atanan yeni değeri döndürür. Bu karmaşık düzenlemenin nedeni, yerleşik olan Lazy<T> içinde çoklu iş parçacığı korumalarını korumaktır. Aksi takdirde, özellik erişimcilerinin, Value özelliği tarafından döndürülen ilk değeri önbelleğe alması ve sadece önbellekteki değeri değiştirmesi gerekirdi; ayrıca, bunu yapabilmek için iş parçacığı güvenliğinde kendi kodunuzu yazmanız gerekirdi. Bir nesne tarafından Lazy<T> yedeklenen bir okuma/yazma özelliğinin gerektirdiği ek başlatma işlemleri nedeniyle, performans kabul edilemez olabilir. Ayrıca, belirli bir senaryoya bağlı olarak, setter'lar ve getter'lar arasındaki 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 verilere iş parçacığı yerel verileri denir. .NET Framework sürüm 3.5 ve önceki sürümlerinde, ThreadStatic
özniteliğini bir statik değişkene uygulayarak onu iş parçacığına özgü yapabilirsiniz. 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 s_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 System.Threading.ThreadLocal<T> temsilcisi tarafından tüm iş parçacıklarında başlatılan türünde bir örnek-tabanlı, iş parçacığına özgü değişken oluşturmak için Action<T> türünü kullanabilirsiniz. Aşağıdaki örnekte, counter
'e erişen tüm iş parçacıkları başlangıç değerini 1 olarak görecektir.
ThreadLocal<int> _betterCounter = new(() => 1);
Dim betterCounter As ThreadLocal(Of Integer) = New ThreadLocal(Of Integer)(Function() 1)
ThreadLocal<T>, Lazy<T> gibi nesnesini sarmalar, ancak şu temel farklarla birlikte:
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.Eğer bir başlatma işlemi temsilcisi sağlanmazsa, ThreadLocal<T> türün varsayılan değerini kullanarak kapsanan türü başlatır. Bu bağlamda ThreadLocal<T>ThreadStaticAttribute özniteliğiyle tutarlıdır.
Aşağıdaki örnek, ThreadLocal<int>
örneğine erişen her iş parçacığının 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(() => Environment.CurrentManagedThreadId);
Thread t4 = new(() => Console.WriteLine($"threadLocalNumber on t4 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t4.Start();
Thread t5 = new(() => Console.WriteLine($"threadLocalNumber on t5 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
t5.Start();
Thread t6 = new(() => Console.WriteLine($"threadLocalNumber on t6 = {threadLocalNumber.Value} ThreadID = {Environment.CurrentManagedThreadId}"));
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çası Yerel Değişkenleri
Veri kaynaklarını paralel olarak yinelemek için Parallel.For yöntemi veya Parallel.ForEach yöntemini kullandığınızda, iş parçacığına özel veriler 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: Thread-Local Değişkenlerle Parallel.For Döngüsü Yazma ve Nasıl yapılır: Partition-Local Değişkenlerle Parallel.ForEach Döngüsü Yazma.
Düşük Yük Senaryoları için Tembel Başlatma Kullanma
Çok sayıda nesneyi tembel başlatmanız gereken senaryolarda, her nesneyi Lazy<T> içinde sarmalamanın çok fazla bellek veya çok fazla bilgi işlem kaynağı gerektirdiğine karar verebilirsiniz. Alternatif olarak, gecikmeli başlatmanın nasıl gösterildiği konusunda kesin gereksinimleriniz olabilir. Böyle durumlarda, her nesneyi bir static
örneğine sarmalamadan önce Shared
sınıfının System.Threading.LazyInitializer (Lazy<T> Visual Basic'te) yöntemlerini kullanarak tembel başlatabilirsiniz.
Aşağıdaki örnekte, bir Orders
nesnesinin tamamını tek bir Lazy<T> nesne içine sarmalamak yerine, sadece gerektiğinde tembel bir şekilde başlatılan ayrı ayrı Order
nesnelerine 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.