Öğretici: Güvenlikle ref
bellek ayırmalarını azaltma
.NET uygulaması için performans ayarlama işlemi genellikle iki teknik içerir. İlk olarak, yığın ayırmalarının sayısını ve boyutunu azaltın. İkinci olarak, verilerin kopyalanan sıklık oranını azaltın. Visual Studio, uygulamanızın belleği nasıl kullandığını analiz etmek için harika araçlar sağlar. Uygulamanızın gereksiz ayırmaları nerede yaptığını belirledikten sonra, bu ayırmaları en aza indirmek için değişiklikler yaparsınız. Türleri türlere struct
dönüştürürsinizclass
. Semantiği korumak ve ek kopyalamayı en aza indirmek için güvenlik özelliklerini kullanırsınızref
.
Bu öğreticide en iyi deneyim için Visual Studio 17.5'i kullanın. Bellek kullanımını analiz etmek için kullanılan .NET nesne ayırma aracı Visual Studio'nun bir parçasıdır. Uygulamayı çalıştırmak ve tüm değişiklikleri yapmak için Visual Studio Code'u ve komut satırını kullanabilirsiniz. Ancak, değişikliklerinizin analiz sonuçlarını göremezsiniz.
Kullanacağınız uygulama, yetkisiz bir kullanıcının değerli eşyalarla gizli bir galeriye girip girmediğini belirlemek için çeşitli algılayıcıları izleyen bir IoT uygulamasının simülasyonudur. IoT algılayıcıları sürekli olarak oksijen (O2) ve karbondioksit (CO2) karışımını ölçen veriler gönderir. Ayrıca sıcaklığı ve göreli nemi de bildirirler. Bu değerlerin her biri her zaman biraz dalgalanıyor. Ancak, bir kişi odaya girdiğinde, değişiklik biraz daha fazla ve her zaman aynı yöndedir: Oksijen azalır, KarbonDioksit artar, sıcaklık artar, göreli nem gibi. Algılayıcılar artacak şekilde bir araya geldiğinde davetsiz misafir alarmı tetikleniyor.
Bu öğreticide uygulamayı çalıştıracak, bellek ayırmalarıyla ilgili ölçümler alacak, ardından ayırma sayısını azaltarak performansı geliştireceksiniz. Kaynak kodu örnekler tarayıcısında kullanılabilir.
Başlangıç uygulamasını keşfetme
Uygulamayı indirin ve başlangıç örneğini çalıştırın. Başlangıç uygulaması düzgün çalışır, ancak her ölçüm döngüsünde çok sayıda küçük nesne ayırdığından, zaman içinde çalıştığından performansı yavaş yavaş düşer.
Press <return> to start simulation
Debounced measurements:
Temp: 67.332
Humidity: 41.077%
Oxygen: 21.097%
CO2 (ppm): 404.906
Average measurements:
Temp: 67.332
Humidity: 41.077%
Oxygen: 21.097%
CO2 (ppm): 404.906
Debounced measurements:
Temp: 67.349
Humidity: 46.605%
Oxygen: 20.998%
CO2 (ppm): 408.707
Average measurements:
Temp: 67.349
Humidity: 46.605%
Oxygen: 20.998%
CO2 (ppm): 408.707
Birçok satır kaldırıldı.
Debounced measurements:
Temp: 67.597
Humidity: 46.543%
Oxygen: 19.021%
CO2 (ppm): 429.149
Average measurements:
Temp: 67.568
Humidity: 45.684%
Oxygen: 19.631%
CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High
Debounced measurements:
Temp: 67.602
Humidity: 46.835%
Oxygen: 19.003%
CO2 (ppm): 429.393
Average measurements:
Temp: 67.568
Humidity: 45.684%
Oxygen: 19.631%
CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High
Uygulamanın nasıl çalıştığını öğrenmek için kodu inceleyebilirsiniz. Ana program simülasyonu çalıştırır. tuşuna bastıktan <Enter>
sonra bir oda oluşturur ve bazı ilk temel verileri toplar:
Console.WriteLine("Press <return> to start simulation");
Console.ReadLine();
var room = new Room("gallery");
var r = new Random();
int counter = 0;
room.TakeMeasurements(
m =>
{
Console.WriteLine(room.Debounce);
Console.WriteLine(room.Average);
Console.WriteLine();
counter++;
return counter < 20000;
});
Bu temel veriler oluşturulduktan sonra, rastgele bir sayı oluşturucunun odaya izinsiz giren bir kullanıcının girip girmediğini belirlediği odada simülasyonu çalıştırır:
counter = 0;
room.TakeMeasurements(
m =>
{
Console.WriteLine(room.Debounce);
Console.WriteLine(room.Average);
room.Intruders += (room.Intruders, r.Next(5)) switch
{
( > 0, 0) => -1,
( < 3, 1) => 1,
_ => 0
};
Console.WriteLine($"Current intruders: {room.Intruders}");
Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");
Console.WriteLine();
counter++;
return counter < 200000;
});
Diğer türlerde ölçüler, son 50 ölçümün ortalaması olan birbounced ölçümü ve alınan tüm ölçümlerin ortalaması yer alır.
Ardından, .NET nesne ayırma aracını kullanarak uygulamayı çalıştırın. Derlemeyi değil derlemeyi Release
kullandığınızdan Debug
emin olun. Hata Ayıkla menüsünde Performans profili oluşturucuyu açın. .NET Nesne Ayırma İzleme seçeneğini işaretleyin, ancak başka bir şey yok. Tamamlanmak için uygulamanızı çalıştırın. Profil oluşturucu, nesne ayırmalarını ölçer ve ayırmaları ve çöp toplama döngülerini raporlar. Aşağıdaki görüntüye benzer bir grafik görmeniz gerekir:
Önceki grafikte ayırmaları en aza indirmek için çalışmanın performans avantajları sağlayacağı gösterilmektedir. Canlı nesneler grafiğinde sawtooth deseni görürsünüz. Bu, hızlı bir şekilde çöpe dönüşen çok sayıda nesnenin oluşturulduğunu bildirir. Bunlar daha sonra nesne delta grafiğinde gösterildiği gibi toplanır. Aşağı doğru kırmızı çubuklar çöp toplama döngüsünü gösterir.
Ardından, grafiklerin altındaki Ayırmalar sekmesine bakın. Bu tablo en çok hangi türlerin ayrıldığını gösterir:
Türü System.String en fazla ayırmayı hesaplar. En önemli görev, dize ayırma sıklığını en aza indirmek olmalıdır. Bu uygulama, konsola sürekli olarak çok sayıda biçimlendirilmiş çıktı yazdırır. Bu benzetim için iletileri tutmak istediğimiz için sonraki iki satıra odaklanacağız: SensorMeasurement
tür ve IntruderRisk
tür.
Satıra SensorMeasurement
çift tıklayın. Tüm ayırmaların yönteminde SensorMeasurement.TakeMeasurement
gerçekleştiğini static
görebilirsiniz. Yöntemini aşağıdaki kod parçacığında görebilirsiniz:
public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
return new SensorMeasurement
{
CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
Room = room,
TimeRecorded = DateTime.Now
};
}
Her ölçüm türü olan yeni SensorMeasurement
bir class
nesne ayırır. Oluşturulan her SensorMeasurement
biri yığın ayırmaya neden olur.
Sınıfları yapılara değiştirme
Aşağıdaki kod, öğesinin ilk bildirimini SensorMeasurement
gösterir:
public class SensorMeasurement
{
private static readonly Random generator = new Random();
public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
return new SensorMeasurement
{
CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
Room = room,
TimeRecorded = DateTime.Now
};
}
private const double CO2Concentration = 409.8; // increases with people.
private const double O2Concentration = 0.2100; // decreases
private const double TemperatureSetting = 67.5; // increases
private const double HumiditySetting = 0.4500; // increases
public required double CO2 { get; init; }
public required double O2 { get; init; }
public required double Temperature { get; init; }
public required double Humidity { get; init; }
public required string Room { get; init; }
public required DateTime TimeRecorded { get; init; }
public override string ToString() => $"""
Room: {Room} at {TimeRecorded}:
Temp: {Temperature:F3}
Humidity: {Humidity:P3}
Oxygen: {O2:P3}
CO2 (ppm): {CO2:F3}
""";
}
Türü başlangıçta çok sayıda double
ölçüm içerdiğinden olarak class
oluşturulmuştur. Sık erişimli yollarda kopyalamak istediğinizden daha büyük. Ancak bu karar çok sayıda ayırma anlamına geliyordu. türünü class
struct
olarak değiştirin.
başvuru kullanılan null
özgün kod birkaç noktada denetlediğinden , class
struct
olarak değiştirerek birkaç derleyici hatasına neden olur. birincisi sınıfında, yöntemindedir DebounceMeasurement
AddMeasurement
:
public void AddMeasurement(SensorMeasurement datum)
{
int index = totalMeasurements % debounceSize;
recentMeasurements[index] = datum;
totalMeasurements++;
double sumCO2 = 0;
double sumO2 = 0;
double sumTemp = 0;
double sumHumidity = 0;
for (int i = 0; i < debounceSize; i++)
{
if (recentMeasurements[i] is not null)
{
sumCO2 += recentMeasurements[i].CO2;
sumO2+= recentMeasurements[i].O2;
sumTemp+= recentMeasurements[i].Temperature;
sumHumidity += recentMeasurements[i].Humidity;
}
}
O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}
Türü DebounceMeasurement
50 ölçümden oluşan bir dizi içerir. Bir algılayıcının okumaları, son 50 ölçümün ortalaması olarak bildirilir. Bu, okumalardaki gürültüyü azaltır. Tam 50 okuma alınmadan önce, bu değerler şeklindedir null
. Kod, sistem başlangıcında doğru ortalamayı raporlamak için null
başvuruyu denetler. Türü bir yapıya SensorMeasurement
değiştirdikten sonra farklı bir test kullanmanız gerekir. Tür SensorMeasurement
, oda tanımlayıcısı için bir string
içerir, bu nedenle bunun yerine bu testi kullanabilirsiniz:
if (recentMeasurements[i].Room is not null)
Diğer üç derleyici hatasının tümü, bir odada tekrar tekrar ölçümler alan yöntemdedir:
public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
{
SensorMeasurement? measure = default;
do {
measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
Average.AddMeasurement(measure);
Debounce.AddMeasurement(measure);
} while (MeasurementHandler(measure));
}
starter yönteminde, öğesinin SensorMeasurement
yerel değişkeni null atanabilir bir başvurudur:
SensorMeasurement? measure = default;
artık yerine bir class
struct
olduğuna göre SensorMeasurement
null atanabilir, null atanabilir bir değer türüdür. Bildirimi bir değer türüyle değiştirerek kalan derleyici hatalarını düzeltebilirsiniz:
SensorMeasurement measure = default;
Artık derleyici hataları giderildiğine göre, semantiğin değişmediğinden emin olmak için kodu incelemeniz gerekir. struct
Türler değere göre geçirildiğinden, yöntem parametrelerinde yapılan değişiklikler yöntem döndürdüğünde görünmez.
Önemli
Bir türü olarak class
struct
değiştirmek, programınızın semantiğini değiştirebilir. Bir yönteme bir class
tür geçirildiğinde, yöntemde yapılan tüm mutasyonlar bağımsız değişkene yapılır. Bir yönteme bir struct
tür geçirildiğinde ve yöntemde yapılan mutasyonlar bağımsız değişkenin bir kopyasına geçirilir. Bu, bağımsız değişkenlerini tasarıma göre değiştiren herhangi bir yöntemin ref
, bir bağımsız değişken türünde değiştirdiğiniz class
herhangi bir struct
bağımsız değişken türünde değiştiriciyi kullanacak şekilde güncelleştirilmesi gerektiği anlamına gelir.
Türü, SensorMeasurement
durumu değiştiren herhangi bir yöntem içermez, bu nedenle bu örnekte sorun olmaz. Değiştiriciyi yapıya readonly
SensorMeasurement
ekleyerek bunu kanıtlayabilirsiniz:
public readonly struct SensorMeasurement
Derleyici, yapının yapısını SensorMeasurement
zorlarreadonly
. Kodu incelemeniz durumu değiştiren bir yöntemi kaçırdıysa, derleyici size bildirir. Uygulamanız hala hatasız derlendiğinden bu tür olur readonly
. bir türü olarak struct
class
değiştirdiğinizde değiştiriciyi readonly
eklemek, durumunu değiştiren üyeleri bulmanıza struct
yardımcı olabilir.
Kopya oluşturmaktan kaçının
Uygulamanızdan çok sayıda gereksiz ayırma kaldırdınız. Tür SensorMeasurement
tabloda hiçbir yerde görünmez.
Şimdi, parametre veya dönüş değeri olarak her kullanıldığında yapıyı SensorMeasurement
kopyalamak için fazladan çalışma yapıyor. YapısıSensorMeasurement
, a ve string
olmak DateTime üzere dört çift içerir. Bu yapı bir başvurudan ölçülebilir derecede büyüktür. Türün ref
kullanıldığı yerlere veya in
değiştiricilerini SensorMeasurement
ekleyelim.
Sonraki adım, ölçü döndüren veya bir ölçümü bağımsız değişken olarak alan yöntemleri bulmak ve mümkün olduğunca başvuruları kullanmaktır. Yapıdan SensorMeasurement
başlayın. Statik TakeMeasurement
yöntem yeni SensorMeasurement
bir oluşturur ve döndürür:
public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
return new SensorMeasurement
{
CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
Room = room,
TimeRecorded = DateTime.Now
};
}
Değere göre döndürerek bunu olduğu gibi bırakacağız. tarafından ref
döndürülmeye çalışsaydınız derleyici hatasıyla karşılaşırsınız. yönteminde yerel olarak oluşturulan yeni bir yapıya döndüremezsiniz ref
. Sabit yapının tasarımı, yalnızca inşaatta ölçümün değerlerini ayarlayabildiğiniz anlamına gelir. Bu yöntem yeni bir ölçüm yapısı oluşturmalıdır.
'a tekrar bakalım DebounceMeasurement.AddMeasurement
. Değiştiriciyi in
parametresine measurement
eklemelisiniz:
public void AddMeasurement(in SensorMeasurement datum)
{
int index = totalMeasurements % debounceSize;
recentMeasurements[index] = datum;
totalMeasurements++;
double sumCO2 = 0;
double sumO2 = 0;
double sumTemp = 0;
double sumHumidity = 0;
for (int i = 0; i < debounceSize; i++)
{
if (recentMeasurements[i].Room is not null)
{
sumCO2 += recentMeasurements[i].CO2;
sumO2+= recentMeasurements[i].O2;
sumTemp+= recentMeasurements[i].Temperature;
sumHumidity += recentMeasurements[i].Humidity;
}
}
O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}
Bu, bir kopyalama işlemini kaydeder. parametresi, in
çağıranın önceden oluşturduğu kopyaya bir başvurudur. Türündeki TakeMeasurement
Room
yöntemiyle bir kopyasını da kaydedebilirsiniz. Bu yöntem, tarafından ref
bağımsız değişkenleri geçirirken derleyicinin nasıl güvenlik sağladığını gösterir. türündeki Room
ilk TakeMeasurement
yöntem, bağımsız değişkenini Func<SensorMeasurement, bool>
alır. Veya ref
değiştiricisini in
bu bildirime eklemeye çalışırsanız, derleyici bir hata bildirir. Lambda ifadesine bağımsız değişken geçiremezsiniz ref
. Derleyici, çağrılan ifadenin başvuruyu kopyalamadığını garanti etmez. Lambda ifadesi başvuruyu yakalarsa , başvurunun ömrü başvurduğu değerden daha uzun olabilir. Başvuru güvenli bağlamı dışında erişim bellek bozulmasına neden olabilir. Güvenlik ref
kuralları buna izin vermiyor. Başvuru güvenliği özelliklerine genel bakış bölümünden daha fazla bilgi edinebilirsiniz.
Semantiği koruma
Türler sık erişimli yollarda oluşturulmadığından, son değişiklik kümelerinin bu uygulamanın performansı üzerinde önemli bir etkisi olmayacaktır. Bu değişiklikler, performans ayarlama işleminizde kullanacağınız diğer tekniklerden bazılarını gösterir. İlk Room
sınıfa göz atalım:
public class Room
{
public AverageMeasurement Average { get; } = new ();
public DebounceMeasurement Debounce { get; } = new ();
public string Name { get; }
public IntruderRisk RiskStatus
{
get
{
var CO2Variance = (Debounce.CO2 - Average.CO2) > 10.0 / 4;
var O2Variance = (Average.O2 - Debounce.O2) > 0.005 / 4.0;
var TempVariance = (Debounce.Temperature - Average.Temperature) > 0.05 / 4.0;
var HumidityVariance = (Debounce.Humidity - Average.Humidity) > 0.20 / 4;
IntruderRisk risk = IntruderRisk.None;
if (CO2Variance) { risk++; }
if (O2Variance) { risk++; }
if (TempVariance) { risk++; }
if (HumidityVariance) { risk++; }
return risk;
}
}
public int Intruders { get; set; }
public Room(string name)
{
Name = name;
}
public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
{
SensorMeasurement? measure = default;
do {
measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
Average.AddMeasurement(measure);
Debounce.AddMeasurement(measure);
} while (MeasurementHandler(measure));
}
}
Bu tür çeşitli özellikler içerir. Bazıları türleridir class
. Room
Nesne oluşturmak için birden çok ayırma gerekir. Biri kendisi için Room
, diğeri de içerdiği bir türün her üyesi class
için. Bu özelliklerden ikisini türlerden class
türlere struct
dönüştürebilirsiniz: DebounceMeasurement
ve AverageMeasurement
türleri. Şimdi bu dönüştürmeyi her iki türle de inceleyelim.
türünü DebounceMeasurement
class
struct
olarak değiştirin. Bu, bir derleyici hatasına CS8983: A 'struct' with field initializers must include an explicitly declared constructor
neden olur. Boş bir parametresiz oluşturucu ekleyerek bunu düzeltebilirsiniz:
public DebounceMeasurement() { }
Bu gereksinim hakkında daha fazla bilgiyi yapılarla ilgili dil başvurusu makalesinde bulabilirsiniz.
Geçersiz Object.ToString() kılma, yapının değerlerinden hiçbirini değiştirmez. Değiştiriciyi readonly
bu yöntem bildirimine ekleyebilirsiniz. Türü DebounceMeasurement
değişebilir, bu nedenle değişikliklerin atılan kopyaları etkilememesi için dikkatli olmanız gerekir. AddMeasurement
yöntemi nesnenin durumunu değiştirir. yönteminde Room
sınıfından çağrılır TakeMeasurements
. Yöntemini çağırdıktan sonra bu değişikliklerin kalıcı olmasını istiyorsunuz. Özelliğini, türün Room.Debounce
tek bir örneğine DebounceMeasurement
başvuru döndürecek şekilde değiştirebilirsiniz:
private DebounceMeasurement debounce = new();
public ref readonly DebounceMeasurement Debounce { get { return ref debounce; } }
Önceki örnekte birkaç değişiklik var. İlk olarak özelliği, bu odanın sahip olduğu örneğe salt okunur bir başvuru döndüren salt okunur bir özelliktir. Artık nesne örneği oluşturulurken Room
başlatılan bildirilen bir alan tarafından destekleniyor. Bu değişiklikleri yaptıktan sonra yönteminin AddMeasurement
uygulamasını güncelleştireceksiniz. Salt okunur özelliğini Debounce
değil, debounce
özel yedekleme alanını kullanır. Bu şekilde, değişiklikler başlatma sırasında oluşturulan tek örnekte gerçekleşir.
Aynı teknik özelliğiyle Average
de çalışır. İlk olarak, türünden AverageMeasurement
class
' struct
a değiştirirsiniz ve yöntemine readonly
değiştiriciyi ToString
eklersiniz:
namespace IntruderAlert;
public struct AverageMeasurement
{
private double sumCO2 = 0;
private double sumO2 = 0;
private double sumTemperature = 0;
private double sumHumidity = 0;
private int totalMeasurements = 0;
public AverageMeasurement() { }
public readonly double CO2 => sumCO2 / totalMeasurements;
public readonly double O2 => sumO2 / totalMeasurements;
public readonly double Temperature => sumTemperature / totalMeasurements;
public readonly double Humidity => sumHumidity / totalMeasurements;
public void AddMeasurement(in SensorMeasurement datum)
{
totalMeasurements++;
sumCO2 += datum.CO2;
sumO2 += datum.O2;
sumTemperature += datum.Temperature;
sumHumidity+= datum.Humidity;
}
public readonly override string ToString() => $"""
Average measurements:
Temp: {Temperature:F3}
Humidity: {Humidity:P3}
Oxygen: {O2:P3}
CO2 (ppm): {CO2:F3}
""";
}
Ardından, sınıfını Room
özelliği için kullandığınız teknikle Debounce
değiştirirsiniz. özelliği, Average
ortalama ölçüm için özel alana bir readonly ref
döndürür. AddMeasurement
yöntemi iç alanları değiştirir.
private AverageMeasurement average = new();
public ref readonly AverageMeasurement Average { get { return ref average; } }
Boks yapmaktan kaçının
Performansı geliştirmek için son bir değişiklik vardır. Ana program, risk değerlendirmesi dahil olmak üzere odanın istatistiklerini yazdırmaktır:
Console.WriteLine($"Current intruders: {room.Intruders}");
Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");
Oluşturulan ToString
kutulara yapılan çağrı, sabit listesi değerini gösterir. Dizeyi Room
tahmini risk değerine göre biçimlendiren sınıfında bir geçersiz kılma yazarak bunu önleyebilirsiniz:
public override string ToString() =>
$"Calculated intruder risk: {RiskStatus switch
{
IntruderRisk.None => "None",
IntruderRisk.Low => "Low",
IntruderRisk.Medium => "Medium",
IntruderRisk.High => "High",
IntruderRisk.Extreme => "Extreme",
_ => "Error!"
}}, Current intruders: {Intruders.ToString()}";
Ardından, ana programdaki kodu şu yeni ToString
yöntemi çağıracak şekilde değiştirin:
Console.WriteLine(room.ToString());
Profil oluşturucuyu kullanarak uygulamayı çalıştırın ve ayırmalar için güncelleştirilmiş tabloya bakın.
Çok sayıda ayırmayı kaldırdınız ve uygulamanıza bir performans artışı sağladınız.
Uygulamanızda başvuru güvenliğini kullanma
Bu teknikler düşük düzeyli performans ayarlamalarıdır. Bunlar, sık erişimli yollara uygulandığında ve değişikliklerin öncesindeki ve sonrasındaki etkiyi ölçtünüzde uygulamanızdaki performansı artırabilir. Çoğu durumda izleyeceğiniz döngü şudur:
- Ölçü ayırmaları: En çok hangi türlerin ayrıldığını ve yığın ayırmalarını ne zaman azaltabileceğinizi belirleyin.
- Sınıfı yapıya dönüştürme: Birçok kez, türler öğesinden öğesine
class
struct
dönüştürülebilir. Uygulamanız yığın ayırmaları yapmak yerine yığın alanı kullanıyor. - Semantiği koruma: '
class
yi öğesinestruct
dönüştürmek, parametrelerin ve dönüş değerlerinin semantiğini etkileyebilir. Parametrelerini değiştiren herhangi bir yöntem artık bu parametreleri değiştirici ileref
işaretlemelidir. Bu, değişikliklerin doğru nesnede yapılmasını sağlar. Benzer şekilde, bir özellik veya yöntem dönüş değeri çağıran tarafından değiştirilmesi gerekiyorsa, bu dönüş değiştirici ileref
işaretlenmelidir. - Kopyalardan kaçının: Büyük bir yapıyı parametre olarak geçirdiğinizde, parametresini
in
değiştirici ile işaretleyebilirsiniz. Bir başvuruyu daha az bayt olarak geçirebilir ve yöntemin özgün değeri değiştirmediğinden emin olabilirsiniz. Değiştirilmeyen bir başvuru döndürmek için ile de değerreadonly ref
döndürebilirsiniz.
Bu teknikleri kullanarak kodunuzun sık erişimli yollarındaki performansı geliştirebilirsiniz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin