Lazy<T> Sınıf
Tanım
Önemli
Bazı bilgiler ürünün ön sürümüyle ilgilidir ve sürüm öncesinde önemli değişiklikler yapılmış olabilir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.
Yavaş başlatma desteği sağlar.
generic <typename T>
public ref class Lazy
public class Lazy<T>
[System.Runtime.InteropServices.ComVisible(false)]
[System.Serializable]
public class Lazy<T>
type Lazy<'T> = class
[<System.Runtime.InteropServices.ComVisible(false)>]
[<System.Serializable>]
type Lazy<'T> = class
Public Class Lazy(Of T)
Tür Parametreleri
- T
Lazily başlatılmakta olan nesnenin türü.
- Devralma
-
Lazy<T>
- Türetilmiş
- Öznitelikler
Örnekler
Aşağıdaki örnek, birden çok iş parçacığından erişimle yavaş başlatma sağlamak için Lazy<T> sınıfının kullanımını gösterir.
Not
Örnekte Lazy<T>(Func<T>) oluşturucu kullanılır. Ayrıca Lazy<T>(Func<T>, Boolean) oluşturucunun (isThreadSafe
için true
belirtme) ve Lazy<T>(Func<T>, LazyThreadSafetyMode) oluşturucunun (mode
için LazyThreadSafetyMode.ExecutionAndPublication belirtme) kullanımını da gösterir. Farklı bir oluşturucuya geçmek için açıklama satırı yapılan oluşturucuları değiştirmeniz gerekir.
Aynı oluşturucuları kullanarak özel durum önbelleğe almayı gösteren bir örnek için bkz. Lazy<T>(Func<T>) oluşturucu.
Örnek, birkaç iş parçacığından biri tarafından yavaş başlatılacak bir LargeObject
sınıfı tanımlar. Kodun dört önemli bölümü başlatıcının oluşturulmasını, fabrika yöntemini, gerçek başlatmayı ve nesne oluşturulduğunda bir ileti görüntüleyen LargeObject
sınıfının oluşturucusunu gösterir.
Main
yönteminin başında, örnek LargeObject
için iş parçacığı güvenli gecikme başlatıcısı oluşturur:
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
// LazyThreadSafetyMode.ExecutionAndPublication);
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject,
// LazyThreadSafetyMode.ExecutionAndPublication)
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
' LazyThreadSafetyMode.ExecutionAndPublication)
Fabrika yöntemi, daha fazla başlatma için bir yer tutucu ile nesnesinin oluşturulmasını gösterir:
static LargeObject InitLargeObject()
{
LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
// Perform additional initialization here.
return large;
}
let initLargeObject () =
let large = LargeObject Thread.CurrentThread.ManagedThreadId
// Perform additional initialization here.
large
Private Shared Function InitLargeObject() As LargeObject
Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
' Perform additional initialization here.
Return large
End Function
İlk iki kod bölümünün burada gösterildiği gibi bir lambda işlevi kullanılarak birleştirilebileceğini unutmayın:
lazyLargeObject = new Lazy<LargeObject>(() =>
{
LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
// Perform additional initialization here.
return large;
});
let lazyLargeObject = Lazy<LargeObject>(fun () ->
let large = LargeObject Thread.CurrentThread.ManagedThreadId
// Perform additional initialization here.
large)
lazyLargeObject = New Lazy(Of LargeObject)(Function ()
Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
' Perform additional initialization here.
Return large
End Function)
Gecikmeli başlatma gerçekleşmeden önce belirsiz bir sürenin geç olabileceğini belirtmek için örnek duraklatılır. Enter ThreadProc
yöntemi Value özelliğini çağırır. Bu ilk kez gerçekleştiğinde LargeObject
örneği oluşturulur:
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
Kodun son anahtar bölümünü içeren LargeObject
sınıfının oluşturucusunun bir ileti görüntüler ve başlatan iş parçacığının kimliğini kaydeder. Programın çıkışı, tam kod listesinin sonunda görüntülenir.
int initBy = 0;
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
type LargeObject(initBy) =
do
printfn $"LargeObject was created on thread id %i{initBy}."
Private initBy As Integer = 0
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Not
Kolaylık olması için, bu örnekte Lazy<T>genel bir örneği kullanılır ve tüm yöntemler static
(Visual Basic'teShared
) kullanılır. Bunlar gecikmeli başlatma kullanımına yönelik gereksinimler değildir.
using System;
using System.Threading;
class Program
{
static Lazy<LargeObject> lazyLargeObject = null;
static LargeObject InitLargeObject()
{
LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
// Perform additional initialization here.
return large;
}
static void Main()
{
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject, true);
//lazyLargeObject = new Lazy<LargeObject>(InitLargeObject,
// LazyThreadSafetyMode.ExecutionAndPublication);
Console.WriteLine(
"\r\nLargeObject is not created until you access the Value property of the lazy" +
"\r\ninitializer. Press Enter to create LargeObject.");
Console.ReadLine();
// Create and start 3 threads, each of which uses LargeObject.
Thread[] threads = new Thread[3];
for (int i = 0; i < 3; i++)
{
threads[i] = new Thread(ThreadProc);
threads[i].Start();
}
// Wait for all 3 threads to finish.
foreach (Thread t in threads)
{
t.Join();
}
Console.WriteLine("\r\nPress Enter to end the program");
Console.ReadLine();
}
static void ThreadProc(object state)
{
LargeObject large = lazyLargeObject.Value;
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock(large)
{
large.Data[0] = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.",
large.InitializedBy, large.Data[0]);
}
}
}
class LargeObject
{
public int InitializedBy { get { return initBy; } }
int initBy = 0;
public LargeObject(int initializedBy)
{
initBy = initializedBy;
Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
}
public long[] Data = new long[100000000];
}
/* This example produces output similar to the following:
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject.
LargeObject was created on thread id 3.
Initialized by thread 3; last used by thread 3.
Initialized by thread 3; last used by thread 4.
Initialized by thread 3; last used by thread 5.
Press Enter to end the program
*/
open System
open System.Threading
type LargeObject(initBy) =
do
printfn $"LargeObject was created on thread id %i{initBy}."
member _.InitializedBy = initBy
member val Data = Array.zeroCreate<int64> 100000000
let initLargeObject () =
let large = LargeObject Thread.CurrentThread.ManagedThreadId
// Perform additional initialization here.
large
// The lazy initializer is created here. LargeObject is not created until the
// ThreadProc method executes.
let lazyLargeObject = Lazy<LargeObject> initLargeObject
// The following lines show how to use other constructors to achieve exactly the
// same result as the previous line:
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject, true)
// let lazyLargeObject = Lazy<LargeObject>(initLargeObject,
// LazyThreadSafetyMode.ExecutionAndPublication)
let threadProc (state: obj) =
let large = lazyLargeObject.Value
// IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
// object after creation. You must lock the object before accessing it,
// unless the type is thread safe. (LargeObject is not thread safe.)
lock large (fun () ->
large.Data[0] <- Thread.CurrentThread.ManagedThreadId
printfn $"Initialized by thread {large.InitializedBy} last used by thread {large.Data[0]}.")
printfn """
LargeObject is not created until you access the Value property of the lazy
initializer. Press Enter to create LargeObject."""
stdin.ReadLine() |> ignore
// Create and start 3 threads, each of which uses LargeObject.
let threads = Array.zeroCreate 3
for i = 0 to 2 do
threads[i] <- Thread(ParameterizedThreadStart threadProc)
threads[i].Start()
// Wait for all 3 threads to finish.
for t in threads do
t.Join()
printfn "\nPress Enter to end the program"
stdin.ReadLine() |> ignore
// This example produces output similar to the following:
// LargeObject is not created until you access the Value property of the lazy
// initializer. Press Enter to create LargeObject.
//
// LargeObject was created on thread id 3.
// Initialized by thread 3 last used by thread 3.
// Initialized by thread 3 last used by thread 4.
// Initialized by thread 3 last used by thread 5.
//
// Press Enter to end the program
Imports System.Threading
Friend Class Program
Private Shared lazyLargeObject As Lazy(Of LargeObject) = Nothing
Private Shared Function InitLargeObject() As LargeObject
Dim large As New LargeObject(Thread.CurrentThread.ManagedThreadId)
' Perform additional initialization here.
Return large
End Function
Shared Sub Main()
' The lazy initializer is created here. LargeObject is not created until the
' ThreadProc method executes.
lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject)
' The following lines show how to use other constructors to achieve exactly the
' same result as the previous line:
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, True)
'lazyLargeObject = New Lazy(Of LargeObject)(AddressOf InitLargeObject, _
' LazyThreadSafetyMode.ExecutionAndPublication)
Console.WriteLine(vbCrLf & _
"LargeObject is not created until you access the Value property of the lazy" _
& vbCrLf & "initializer. Press Enter to create LargeObject.")
Console.ReadLine()
' Create and start 3 threads, each of which uses LargeObject.
Dim threads(2) As Thread
For i As Integer = 0 To 2
threads(i) = New Thread(AddressOf ThreadProc)
threads(i).Start()
Next i
' Wait for all 3 threads to finish.
For Each t As Thread In threads
t.Join()
Next t
Console.WriteLine(vbCrLf & "Press Enter to end the program")
Console.ReadLine()
End Sub
Private Shared Sub ThreadProc(ByVal state As Object)
Dim large As LargeObject = lazyLargeObject.Value
' IMPORTANT: Lazy initialization is thread-safe, but it doesn't protect the
' object after creation. You must lock the object before accessing it,
' unless the type is thread safe. (LargeObject is not thread safe.)
SyncLock large
large.Data(0) = Thread.CurrentThread.ManagedThreadId
Console.WriteLine("Initialized by thread {0}; last used by thread {1}.", _
large.InitializedBy, large.Data(0))
End SyncLock
End Sub
End Class
Friend Class LargeObject
Public ReadOnly Property InitializedBy() As Integer
Get
Return initBy
End Get
End Property
Private initBy As Integer = 0
Public Sub New(ByVal initializedBy As Integer)
initBy = initializedBy
Console.WriteLine("LargeObject was created on thread id {0}.", initBy)
End Sub
Public Data(99999999) As Long
End Class
' This example produces output similar to the following:
'
'LargeObject is not created until you access the Value property of the lazy
'initializer. Press Enter to create LargeObject.
'
'LargeObject was created on thread id 3.
'Initialized by thread 3; last used by thread 3.
'Initialized by thread 3; last used by thread 5.
'Initialized by thread 3; last used by thread 4.
'
'Press Enter to end the program
'
Açıklamalar
Özellikle programın ömrü boyunca böyle bir oluşturma veya yürütme gerçekleşemediğinde, büyük veya kaynak yoğunluklu bir nesnenin oluşturulmasını veya yoğun kaynak kullanan bir görevin yürütülmesini ertelemek için gecikmeli başlatmayı kullanın.
Yavaş başlatmaya hazırlanmak için bir Lazy<T>örneği oluşturursunuz. Oluşturduğunuz Lazy<T> nesnesinin tür bağımsız değişkeni, yavaş başlatmak istediğiniz nesnenin türünü belirtir. Lazy<T> nesnesini oluşturmak için kullandığınız oluşturucu, başlatmanın özelliklerini belirler. Gecikmeli başlatma, Lazy<T>.Value özelliğine ilk kez erişildiğinde gerçekleşir.
Çoğu durumda, bir oluşturucu seçmek iki soruya yanıtlarınıza bağlıdır:
Yavaş başlatılan nesneye birden fazla iş parçacığından erişilecek mi? Bu durumda, Lazy<T> nesnesi herhangi bir iş parçacığında oluşturabilir. Varsayılan davranışı iş parçacığı açısından güvenli bir Lazy<T> nesnesi oluşturmak olan basit oluşturuculardan birini kullanabilirsiniz; böylece, kaç iş parçacığı erişmeye çalışırsa çalışsın, lazily örneklenen nesnenin yalnızca bir örneği oluşturulur. İş parçacığı güvenli olmayan bir Lazy<T> nesnesi oluşturmak için, iş parçacığı güvenliği belirtmenize olanak tanıyan bir oluşturucu kullanmanız gerekir.
Dikkat
Lazy<T> nesne iş parçacığının güvenli hale getirilmesi, lazily initialized nesnesini korumaz. Birden çok iş parçacığı, yavaş başlatılan nesneye erişebiliyorsa, özelliklerini ve yöntemlerini çok iş parçacıklı erişim için güvenli hale getirmeniz gerekir.
Yavaş başlatma çok fazla kod mu gerektiriyor yoksa lazily initialized nesnesinin ihtiyacınız olan her şeyi yapıp özel durumlar oluşturmayan parametresiz bir oluşturucu mu var? Başlatma kodu yazmanız gerekiyorsa veya özel durumların işlenmesi gerekiyorsa, fabrika yöntemi alan oluşturuculardan birini kullanın. Başlatma kodunuzu fabrika yöntemine yazın.
Aşağıdaki tabloda, bu iki faktöre göre hangi oluşturucunun seçileceği gösterilmektedir:
Nesneye | Başlatma kodu gerekmiyorsa (parametresiz oluşturucu) | Başlatma kodu gerekiyorsa |
---|---|---|
Birden çok iş parçacığı | Lazy<T>() | Lazy<T>(Func<T>) |
Bir iş parçacığı |
isThreadSafe
false olarak ayarlanmış Lazy<T>(Boolean). |
isThreadSafe
false olarak ayarlanmış Lazy<T>(Func<T>, Boolean). |
Fabrika yöntemini belirtmek için lambda ifadesi kullanabilirsiniz. Bu, tüm başlatma kodunu tek bir yerde tutar. Lambda ifadesi, lazily initialized nesnesinin oluşturucusna geçirdiğiniz bağımsız değişkenler de dahil olmak üzere bağlamı yakalar.
Özel durum önbelleğe alma Fabrika yöntemlerini kullandığınızda özel durumlar önbelleğe alınır. Yani, bir iş parçacığı Lazy<T> nesnesinin Value özelliğine ilk kez erişmeye çalıştığında fabrika yöntemi bir özel durum oluşturursa, sonraki her girişimde aynı özel durum oluşturulur. Bu, Value özelliğine yapılan her çağrının aynı sonucu üretmesini sağlar ve farklı iş parçacıkları farklı sonuçlar alırsa ortaya çıkabilecek küçük hataları önler.
Lazy<T>, aksi takdirde genellikle başlangıç sırasında daha önceki bir noktada başlatılmış olan gerçek bir T
anlamına gelir. Bu önceki noktadaki bir hata genellikle ölümcüldür. Kurtarılabilir bir hata olasılığı varsa, yavaş başlatma kullanmadığınız durumlarda yaptığınız gibi yeniden deneme mantığını başlatma yordamına (bu örnekte fabrika yöntemi) derlemenizi öneririz.
kilitlemeye alternatif olarak, bazı durumlarda Lazy<T> nesnesinin varsayılan kilitleme davranışının yükünü önlemek isteyebilirsiniz. Nadir durumlarda kilitlenme olasılığı olabilir. Böyle durumlarda, Lazy<T>(LazyThreadSafetyMode) veya Lazy<T>(Func<T>, LazyThreadSafetyMode) oluşturucuyu kullanabilir ve LazyThreadSafetyMode.PublicationOnlybelirtebilirsiniz. Bu, iş parçacıkları aynı anda Value özelliğini çağırırsa, Lazy<T> nesnesinin birkaç iş parçacığında lazily olarak başlatılan nesnenin bir kopyasını oluşturmasını sağlar. Lazy<T> nesnesi, tüm iş parçacıklarının lazily olarak başlatılan nesnenin aynı örneğini kullanmasını sağlar ve kullanılmayan örnekleri atar. Bu nedenle, kilitleme ek yükünü azaltmanın maliyeti, programınızın bazen pahalı bir nesnenin ek kopyalarını oluşturup atabileceğidir. Çoğu durumda, bu pek olası değildir. Lazy<T>(LazyThreadSafetyMode) ve Lazy<T>(Func<T>, LazyThreadSafetyMode) oluşturucuları için örnekler bu davranışı gösterir.
Önemli
LazyThreadSafetyMode.PublicationOnlybelirttiğinizde, fabrika yöntemi belirtseniz bile özel durumlar hiçbir zaman önbelleğe alınmaz.
Eşdeğer oluşturucularLazyThreadSafetyMode.PublicationOnlykullanımını etkinleştirmeye ek olarak, Lazy<T>(LazyThreadSafetyMode) ve Lazy<T>(Func<T>, LazyThreadSafetyMode) oluşturucuları diğer oluşturucuların işlevselliğini çoğaltabilir. Aşağıdaki tabloda eşdeğer davranış üreten parametre değerleri gösterilmektedir.
Lazy<T> nesnesi oluşturmak için |
LazyThreadSafetyMode
mode parametresi olan oluşturucular için mode olarak ayarlayın |
Boole isThreadSafe parametresi olan oluşturucular için isThreadSafe olarak ayarlayın |
İş parçacığı güvenlik parametresi olmayan oluşturucular için |
---|---|---|---|
Tamamen iş parçacığı güvenli; yalnızca bir iş parçacığının değeri başlatmasını sağlamak için kilitlemeyi kullanır. | ExecutionAndPublication | true |
Tüm bu oluşturucular tamamen iş parçacığı güvenlidir. |
İş 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. |
Oluşturucular
Lazy<T>() |
Lazy<T> sınıfının yeni bir örneğini başlatır. Yavaş başlatma gerçekleştiğinde, hedef türün parametresiz oluşturucu kullanılır. |
Lazy<T>(Boolean) |
Lazy<T> sınıfının yeni bir örneğini başlatır. Yavaş başlatma gerçekleştiğinde, hedef türün parametresiz oluşturucu ve belirtilen başlatma modu kullanılır. |
Lazy<T>(Func<T>) |
Lazy<T> sınıfının yeni bir örneğini başlatır. Gecikmeli başlatma gerçekleştiğinde, belirtilen başlatma işlevi kullanılır. |
Lazy<T>(Func<T>, Boolean) |
Lazy<T> sınıfının yeni bir örneğini başlatır. Gecikmeli başlatma gerçekleştiğinde, belirtilen başlatma işlevi ve başlatma modu kullanılır. |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
Belirtilen başlatma işlevini ve iş parçacığı güvenliği modunu kullanan Lazy<T> sınıfının yeni bir örneğini başlatır. |
Lazy<T>(LazyThreadSafetyMode) |
|
Lazy<T>(T) |
Lazy<T> sınıfının önceden tanımlanmış bir değer kullanan yeni bir örneğini başlatır. |
Özellikler
IsValueCreated |
Bu Lazy<T> örneği için bir değer oluşturulup oluşturulmadığını gösteren bir değer alır. |
Value |
Geçerli Lazy<T> örneğinin yavaş başlatılan değerini alır. |
Yöntemler
Equals(Object) |
Belirtilen nesnenin geçerli nesneye eşit olup olmadığını belirler. (Devralındığı yer: Object) |
GetHashCode() |
Varsayılan karma işlevi işlevi görür. (Devralındığı yer: Object) |
GetType() |
Geçerli örneğin Type alır. (Devralındığı yer: Object) |
MemberwiseClone() |
Geçerli Objectbasit bir kopyasını oluşturur. (Devralındığı yer: Object) |
ToString() |
Bu örnek için Value özelliğinin dize gösterimini oluşturur ve döndürür. |
Şunlara uygulanır
İş Parçacığı Güvenliği
Varsayılan olarak, Lazy<T> sınıfının tüm genel ve korumalı üyeleri iş parçacığı güvenlidir ve birden çok iş parçacığından eşzamanlı olarak kullanılabilir. Bu iş parçacığı güvenliği garantileri, türün oluşturucularına yönelik parametreler kullanılarak isteğe bağlı olarak ve örnek başına kaldırılabilir.