Bir değeri kabul edip başka bir değer döndüren ve işlev dışında hiçbir şeyi rahatsız etmeyen bir fonksiyonun hiçbir yan etkisi yoktur ve bu nedenle iş parçacığı için güvenlidir. İşlevin çalışma şeklini güç tüketimini nasıl etkilediğini düşünmek istiyorsanız, bu farklı bir problemdir.
Uygulama detaylarının alakasız olduğu bir tür iyi tanımlanmış programlama dili yürüten Turing-tamamlanmış bir makineye atıfta bulunduğunuzu farz ediyorum. Başka bir deyişle, yığının ne yaptığı önemli değil, eğer programlama dilimde yazdığım fonksiyon dilin sınırları içindeki değişmezliği garanti edebilir. Yüksek seviyede bir dilde programlama yaparken yığın hakkında düşünmüyorum, ne de yapmamalıyım.
Bunun nasıl çalıştığını göstermek için, C # 'da birkaç basit örnek sunacağım. Bu örneklerin doğru olması için birkaç varsayımda bulunmak zorundayız. Birincisi, derleyici C # belirtimini hatasız takip eder ve ikincisi doğru programları üretir.
Bir dize koleksiyonunu kabul eden basit bir işlev istiyorum ve koleksiyondaki tüm dizelerin virgülle ayrılmış bir dizilimi olan bir dize döndürür diyelim. C # 'daki basit, naif bir uygulama şöyle görünebilir:
public string ConcatenateWithCommas(ImmutableList<string> list)
{
string result = string.Empty;
bool isFirst = false;
foreach (string s in list)
{
if (isFirst)
result += s;
else
result += ", " + s;
}
return result;
}
Bu örnek değişmez, prima facie. Bunu nasıl bilebilirim? Çünkü string
nesne değişmez. Ancak, uygulama ideal değildir. Çünkü result
değişmez, yeni dize nesne orijinal nesneyi değiştirerek döngü içinde her zaman yaratılmak zorunda result
işaret ettiği. Bu, fazladan telleri temizlemek zorunda kaldığından, hızı olumsuz yönde etkileyebilir ve çöp toplayıcıya baskı uygulayabilir.
Şimdi şunu yapalım diyelim:
public string ConcatenateWithCommas(ImmutableList<string> list)
{
var result = new StringBuilder();
bool isFirst = false;
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
Değiştirilebilir string
result
bir nesneyle değiştirdiğime dikkat edin StringBuilder
. Bu ilk örnekten çok daha hızlıdır, çünkü döngü boyunca her seferinde yeni bir dize oluşturulmaz. Bunun yerine, StringBuilder nesnesi yalnızca her dizeden gelen karakterleri bir karakter koleksiyonuna ekler ve sonunda her şeyi çıkarır.
StringBuilder değişken olmasına rağmen bu işlev değişmez mi?
Evet öyle. Neden? Çünkü her zaman bu fonksiyon denir, yeni bir StringBuilder sadece bu çağrı için oluşturulur. Şimdi iş parçacığı güvenli, ancak değişken bileşenleri içeren saf bir işleve sahibiz.
Ama ya bunu yaparsam?
public class Concatenate
{
private StringBuilder result = new StringBuilder();
bool isFirst = false;
public string ConcatenateWithCommas(ImmutableList<string> list)
{
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
}
Bu yöntem iş parçacığı güvenli midir? Hayır değil. Neden? Çünkü sınıf şimdi metodumun dayandığı durumu elinde tutuyor. Artık yöntemde bir yarış durumu var: bir iplik değişebilir IsFirst
, ancak başka bir iplik ilkini gerçekleştirebilir, Append()
bu durumda dizimin başlangıcında olması gerekmeyen bir virgül var.
Neden böyle yapmak isteyeyim ki? Konuların result
sırasına bakmaksızın ya da konuların girdiği sıraya göre ipleri biriktirmesini isteyebilirim . Belki de bir logger, kim bilir?
Her neyse, düzeltmek için, lock
yöntemin doğaçlamalarının etrafına bir ifade koydum .
public class Concatenate
{
private StringBuilder result = new StringBuilder();
bool isFirst = false;
private static object locker = new object();
public string AppendWithCommas(ImmutableList<string> list)
{
lock (locker)
{
foreach (string s in list)
{
if (isFirst)
result.Append(s);
else
result.Append(", " + s);
}
return result.ToString();
}
}
}
Şimdi yine iplik güvenli.
Değişmez yöntemlerimin muhtemelen güvenli bir şekilde iş parçacığı için güvenli olamamasının tek yolu, yöntemin bir şekilde uygulamasının bir kısmını sızdırmasıdır. Bu olabilir mi? Derleyici doğru ve program doğru ise. Bu tür yöntemler için kilitlere ihtiyacım olacak mı? Hayır.
Bir eşzamanlılık senaryosunda uygulamanın nasıl sızabileceğine dair bir örnek için, buraya bakın .
but everything has a side effect
- Hayır, değil. Bir değeri kabul eden ve başka bir değer veren ve işlev dışında hiçbir şeyi rahatsız etmeyen bir fonksiyonun hiçbir yan etkisi yoktur ve bu nedenle iş parçacığı için güvenlidir. Bilgisayarın elektrik kullanması önemli değil. İsterseniz bellek hücrelerine de vuran kozmik ışınlardan bahsedebiliriz, isterseniz argümanı pratik tutalım. İşlevin çalışma şeklini güç tüketimini nasıl etkilediğini düşünmek istiyorsanız, bu güvenli bir programlamaya göre farklı bir problemdir.