Thread overview
Başlangıç düzeyi dizi birikintisi(array pool)
Dec 15, 2022
Can Alpay Çiftci
Dec 15, 2022
Ali Çehreli
Dec 15, 2022
Can Alpay Çiftci
Dec 15, 2022
Ali Çehreli
Dec 16, 2022
Can Alpay Çiftci
Dec 16, 2022
Ali Çehreli
Dec 16, 2022
Can Alpay Çiftci
Dec 16, 2022
Ali Çehreli
Dec 16, 2022
Salih Dincer
Dec 16, 2022
Salih Dincer
December 15, 2022

Esenlikler

D'de neleri anımsıyorum diye bakmak için Dotnet kütüphanesinde var olan çöp toplayacıdaki baskıyı azaltmak için kullanılar array pool'u D'de de gerçekleştireyim istedim.

Sanırım çalışır işe yarabilir durumda. En azından öyle umuyorum.

Ancak // private static immutable ArrayPool s_shared = new ConfigurableArrayPool();
yorum satırını sildiğimdeki hatanın mantığını anlayamadım.

module array_pool;
template MyTemplate(T)
{
    public abstract class ArrayPool
    {
        // @property
        // public static auto sharedPool()
        // {
        //     return s_shared;
        // }

        @property
        public static auto create()
        {
            return new ConfigurableArrayPool();
        }

        @property
        public static auto create(size_t maxArrayLength, size_t maxArraysPerBucket)
        {
            return new ConfigurableArrayPool(maxArrayLength, maxArraysPerBucket);
        }

        /*
 Error: pointer cast from `array_pool.MyTemplate!(MyClass).ConfigurableArrayPool` to `void*` is not supported at compile time
source\array_pool.d(70,39):        called from here: `this.toHash()`
source\array_pool.d(57,29):        called from here: `this.id()`
source\array_pool.d(41,17):        called from here: `this.this(1048576LU, 50LU)`
*/
        // private static immutable ArrayPool s_shared = new ConfigurableArrayPool();

        public abstract T[] rent(size_t minimumLength);

        public abstract void returnToPool(T[] array, bool clearArray = false);
    }

    final public class ConfigurableArrayPool : ArrayPool
    {
        private enum size_t defaultMaxArrayLength = 1024 * 1024;
        private enum size_t defaultMaxNumberOfArraysPerBucket = 50;

        private  /*immutable*/ Bucket[] buckets;

        public this()
        {
            this(defaultMaxArrayLength, defaultMaxNumberOfArraysPerBucket);
        }

        public this(size_t maxArrayLength, size_t maxArraysPerBucket)
        {

            enum size_t minumumArrayLength = 0x10;
            enum size_t maximumArrayLength = 0x40000000;
            if (maxArrayLength > maximumArrayLength)
            {
                maxArrayLength = maximumArrayLength;
            }
            else if (maxArrayLength < minumumArrayLength)
            {
                maxArrayLength = minumumArrayLength;
            }
            size_t poolId = id;
            size_t maxBuckets = Utilities.selectBucketIndex(maxArrayLength);
            auto buckets = new Bucket[maxBuckets + 1];
            for (size_t i = 0; i < buckets.length; i++)
            {
                buckets[i] = new Bucket(Utilities.getMaxSizeForBucket(i), maxArraysPerBucket, poolId);
            }
            this.buckets = buckets;
        }

        @property
        size_t id()
        {
            return cast(size_t) toHash();
        }

        public override T[] rent(size_t minimumLength)
        {
            if (minimumLength == 0)
            {
                return new T[0];
            }

            T[] buffer;

            size_t index = Utilities.selectBucketIndex(cast(size_t) minimumLength);
            if (index < buckets.length)
            {
                enum maxBucketsToTry = 2;
                size_t i = index;
                do
                {
                    buffer = this.buckets[i].rent();
                    if (buffer != null)
                    {
                        return buffer;
                    }
                }
                while (++i < this.buckets.length && i != index + maxBucketsToTry);

                buffer = new T[this.buckets[index].bufferLength];
            }
            else
            {
                buffer = new T[minimumLength];
            }

            return buffer;
        }

        public override void returnToPool(T[] array, bool clearArray = false)
        {
            if (array.length == 0)
            {
                return;
            }
            size_t bucketsize_t = Utilities.selectBucketIndex(cast(size_t) array.length);
            bool haveBucket = bucketsize_t < this.buckets.length;

            if (haveBucket)
            {
                if (clearArray)
                {
                    for (size_t i = 0; i < array.length; i++)
                    {
                        array[i] = T.init;
                    }
                }
                this.buckets[bucketsize_t].returnToPool(array);
            }

        }

        final class Bucket
        {
            private immutable size_t bufferLength;
            private  /*immutable*/ T[][] buffers;
            private immutable size_t poolId;

            import core.sync.mutex;
            Mutex mutex;

            private size_t index;

            this(size_t bufferLength, size_t numberOfBuffers, size_t poolId)
            {
                mutex = new Mutex();
                this.buffers = new T[][numberOfBuffers];
                this.bufferLength = bufferLength;
                this.poolId = poolId;
            }

            @property
            size_t id()
            {
                return cast(size_t) toHash();
            }

            T[] rent()
            {
                T[] buffer = null;
                bool lockTaken = false;
                bool allocateBuffer = false;
                try
                {
                    lockTaken = mutex.tryLock_nothrow();

                    if (index < buffers[].length)
                    {
                        buffer = buffers[][index];
                        buffers[][index++] = null;
                        allocateBuffer = buffer == null;
                    }
                }

                finally
                {
                    if (lockTaken)
                    {
                        mutex.tryLock_nothrow();
                    }
                }

                if (allocateBuffer)
                {
                    buffer = new T[bufferLength];
                }
                return buffer;
            }

            void returnToPool(T[] array)
            {
                if (array.length != bufferLength)
                {
                    throw new Exception("Buffer not From Pool");
                }

                bool returned;

                bool lockTaken = false;

                try
                {
                    lockTaken = mutex.tryLock_nothrow();
                    returned = index != 0;
                    if (returned)
                    {
                        buffers[][--index] = array;
                    }
                }
                finally
                {
                    if (lockTaken)
                    {
                        mutex.unlock_nothrow();
                    }
                }
            }

        }

        static class Utilities
        {
            static size_t selectBucketIndex(size_t bufferSize)
            {
                import std.math.exponential;
                return cast(size_t) log2(cast(size_t) bufferSize - 1 | 15) - 3;
            }

            static size_t getMaxSizeForBucket(size_t binIndex)
            {
                size_t maxSize = 16 << binIndex;
                return maxSize;
            }
        }
    }
}

örnek kullanımı:

import std.stdio;
import array_pool;

public class MyClass
{
	public int A;
	public int B;
}

import std.random;

int main(string[] args)
{
	auto _buckets = MyTemplate!(MyClass).ArrayPool.create;

	foreach (key; 1 .. 100)
	{

		auto rnd = Random(unpredictableSeed);
		auto items = _buckets.rent(100);
		for (int i = 0; i < items.length; i++)
		{
			items[i] = new MyClass();
			items[i].A = cast(int) i;
			items[i].B = uniform(0, 100, rnd);
			rnd.popFront;
		}

		foreach (item; items)
		{
			writeln(item.A);
			writeln(item.B);
		}

		_buckets.returnToPool(items, true);
	}
	return 0;
}

December 15, 2022
Başlangıç düzeyi böyleyse biz yanmışız hocam! :p

On 12/15/22 09:37, Can Alpay Çiftci wrote:

> Sanırım çalışır işe yarabilir durumda.

Bende hata verdi:

  Aborted (core dumped)

gdb ile bakınca çöp toplayıcının son temizliği sırasında olduğunu görüyorum:

#0  0x00007ffff7d3264c in ?? () from /usr/lib/libc.so.6
#1  0x00007ffff7ce2958 in raise () from /usr/lib/libc.so.6
#2  0x00007ffff7ccc53d in abort () from /usr/lib/libc.so.6
#3  0x00005555556046cf in core.internal.abort.abort(scope immutable(char)[], scope immutable(char)[], ulong) ()
#4  0x00005555555f78e1 in core.sync.mutex.Mutex.~this() ()
#5  0x0000555555609c87 in rt_finalize2 ()
#6  0x0000555555643667 in rt_finalizeFromGC ()
#7  0x000055555563ad19 in core.internal.gc.impl.conservative.gc.Gcx.sweep() ()
[...]

Bu tür sorunlar çoğunlukla sonlandırıcıda bellek ayırırken falan olur ama senin kodda öyle bir şey de göremiyorum. Belki biraz sonra anlarım.

>          /*
>   Error: pointer cast from
> `array_pool.MyTemplate!(MyClass).ConfigurableArrayPool` to `void*` is
> not supported at compile time
> source\array_pool.d(70,39):        called from here: `this.toHash()`
> source\array_pool.d(57,29):        called from here: `this.id()`
> source\array_pool.d(41,17):        called from here:
> `this.this(1048576LU, 50LU)`
> */
>          // private static immutable ArrayPool s_shared = new
> ConfigurableArrayPool();

Derleme zamanında izin verilmiyorsa ben şöyle değiştirdim:

        private static immutable ArrayPool s_shared;

        shared static this() {
            s_shared = cast(immutable)new ConfigurableArrayPool();
        }

Ancak o 'immutable'dan emin değilim. D bu konuda fazla sıkı: Yalnızca s_shared değil, bütün ArrayPool işlemleri de 'immutable' arayacaklar ve bulamayacaklar. Örneğin, hiçbir üye işlev 'immutable' olarak yazılmamış (zaten bazıları da herhalde immutable yazılamaz).

Ben 'immutable' anahtar sözcüğünü yalnızca gereken yerlere koyuyorum. Yerel değişkenleri de önce 'const' yapıyorum. 'immutable'un istekleri fazla kısıtlayıcı olabiliyor.

>              enum size_t minumumArrayLength = 0x10;

Ünemsiz ;) bir typo: minimum olacak.

>                  bool lockTaken = false;

Zor bir koda benziyor. lockTaken gibi durum değişkenleri şüphe uyandırıyor: Bazı hatalar böyle değişkenlerin etrafında toplanır.

>                      lockTaken = mutex.tryLock_nothrow();

Ben kilit gerektiğinde öncelikle 'synchronized' olanağını düşünüyorum. Ama böyle bir kodda D'nin "thread-local by default" özelliğinden de yararlanabilir: Bütün programın paylaştığı tek pool olacağına her iş parçacığının kendi pool'u olabilir.

Ben buna benzer bir yöntemi şurada gösteriyorum:

  https://youtu.be/dRORNQIB2wA?t=788

ArrayPool tabii ki daha genel bir çözüm ama her iş parçacığının gösterdiğim gibi kendine özgü belleğinin olması beni mutlu ediyor. :) Kilit yok, karmaşıklık yok...


>          auto rnd = Random(unpredictableSeed);

Bir döngü içinde 'rnd' üretip kullanmak yerine uniform'u doğrudan da çağırabilirsin:

>              items[i].B = uniform(0, 100);

unpredictableSeed yerine belirli bir değer kullansan aynı diziyi üretmek istediğini düşüneceğim ama burada gerek yokmuş gibi görünüyor.

Ali

December 15, 2022
On Thursday, 15 December 2022 at 19:01:46 UTC, Ali Çehreli wrote:

> Bende hata verdi:
>
>   Aborted (core dumped)

Ben bu hatayı tetikletemiyorum. "'C:\dmd2\windows\bin64\dub.exe' 'build' '--compiler=dmd.EXE' '--arch=x86_64' '--build=debug' '--config=application'" biçiminde derliyorum. Win11'de.

Hiç bir değişiklik yapmadan mı tetikleyebildiniz? mutex.d sanki posix'de ayrı çalıştırma rutini olduğu için alınmış bir hata gibi geldi bana. destroy ile de çağırdım.


> >   Error: pointer cast from
> > `array_pool.MyTemplate!(MyClass).ConfigurableArrayPool` to
> `void*` is
> > not supported at compile time
> > source\array_pool.d(70,39):        called from here:
> `this.toHash()`
> > source\array_pool.d(57,29):        called from here:
> `this.id()`
> > source\array_pool.d(41,17):        called from here:
> > `this.this(1048576LU, 50LU)`
> > */
> >          // private static immutable ArrayPool s_shared = new
> > ConfigurableArrayPool();
>
> Derleme zamanında izin verilmiyorsa ben şöyle değiştirdim:
>
>         private static immutable ArrayPool s_shared;
>
>         shared static this() {
>             s_shared = cast(immutable)new ConfigurableArrayPool();
>         }

Evet bu çalıştı. static this() {} ile direkt yanında atamanın neredeyse aynı olduğunu düşünüyordum. sanırım değilmiş. Ayrıca değişkenler threadlocal olduğunu tahmin edemezdim sanırım. Şaşırdım.

tabii toHash'i de ezebilirdim ancak bu kezde mutex hata veriyor. Yukarıdaki farklı olduğunu öğrendiğim iyi oldu.

> Ancak o 'immutable'dan emin değilim. D bu konuda fazla sıkı: Yalnızca s_shared değil, bütün ArrayPool işlemleri de 'immutable' arayacaklar ve bulamayacaklar. Örneğin, hiçbir üye işlev 'immutable' olarak yazılmamış (zaten bazıları da herhalde immutable yazılamaz).

> Ben 'immutable' anahtar sözcüğünü yalnızca gereken yerlere koyuyorum. Yerel değişkenleri de önce 'const' yapıyorum. 'immutable'un istekleri fazla kısıtlayıcı olabiliyor.

aslında readonly olması istiyorum. Yani kullanıcı tarafından başka bir adrese atanmamasını istiyorum. const bunun için yeterli sanırım.


>
> >              enum size_t minumumArrayLength = 0x10;
>
> Ünemsiz ;) bir typo: minimum olacak.
>
Mökemmel :-)

>
> >                      lockTaken = mutex.tryLock_nothrow();
>
> Ben kilit gerektiğinde öncelikle 'synchronized' olanağını düşünüyorum. Ama böyle bir kodda D'nin "thread-local by default" özelliğinden de yararlanabilir: Bütün programın paylaştığı tek pool olacağına her iş parçacığının kendi pool'u olabilir.
> Ben buna benzer bir yöntemi şurada gösteriyorum:
>
>   https://youtu.be/dRORNQIB2wA?t=788
>
> ArrayPool tabii ki daha genel bir çözüm ama her iş parçacığının gösterdiğim gibi kendine özgü belleğinin olması beni mutlu ediyor. :) Kilit yok, karmaşıklık yok...

Ben dinamik dizide bunlar zaten vardır diye bekliyordum aslında. Yeni bir şeyi eskisini hiyerarşide kullanarak üretmek yerine sarmallayarak üretmek alışkın olmadığım bakış açısı. Ancak iyimiş. Aslında bu direkt olarak ArrayPool gereksinimi kaldırmıyor. Ancak bununla da gerçekleştirimi yapılırsa yine şık bir şey ortaya çıkabilir.

Gerisini de izleyeceğim bu tarz videoları aşırı beğeniyorum.

> >          auto rnd = Random(unpredictableSeed);
>
> Bir döngü içinde 'rnd' üretip kullanmak yerine uniform'u doğrudan da çağırabilirsin:
>
> >              items[i].B = uniform(0, 100);
>
> unpredictableSeed yerine belirli bir değer kullansan aynı diziyi üretmek istediğini düşüneceğim ama burada gerek yokmuş gibi görünüyor.

Teşekkürler. Bir kopyala yapıştır faciası. std.random koduna girip unittestinden çalışan bir kodu kopyalayıp yapıştırdım :-P

D'nin yalnız derleme hatalarındaki iletiler kimi zamanlarda aşırı iyi. Arada da anlayamayıp gelişigüzel kod değiştirdiğim oldu. Biraz sözdizimi bana alıştığımdan ayrı geldiği için olabilir.

December 15, 2022
On 12/15/22 13:30, Can Alpay Çiftci wrote:
> On Thursday, 15 December 2022 at 19:01:46 UTC, Ali Çehreli wrote:
>
>> Bende hata verdi:
>>
>>   Aborted (core dumped)
>
> Ben bu hatayı tetikletemiyorum. "'C:\dmd2\windows\bin64\dub.exe' 'build'
> '--compiler=dmd.EXE' '--arch=x86_64' '--build=debug'
> '--config=application'" biçiminde derliyorum. Win11'de.
>
> Hiç bir değişiklik yapmadan mı tetikleyebildiniz? mutex.d sanki posix'de
> ayrı çalıştırma rutini olduğu için alınmış bir hata gibi geldi bana.
> destroy ile de çağırdım.

Evet, hiçbir değişiklik yapmadan patlıyor. Ben Linux üzerindeyim. Birazdan anlamaya çalışırım. Buldum:

                finally
                {
                    if (lockTaken)
                    {
                        mutex.tryLock_nothrow();
                    }
                }

unlock_nothrow olacakmış.

Fakat tryLock_nothrow'un döndürdüğü değeri doğru kullandığından emin misin? (Belgesi pek açıklayıcı değil.) 'false' döndürdüğünde işine devam etme hakkın oluyor mu? Çünkü kilitle(ye)mediğinde 'false' döndürüyormuş.

>> >          // private static immutable ArrayPool s_shared = new
>> > ConfigurableArrayPool();
>>
>> Derleme zamanında izin verilmiyorsa ben şöyle değiştirdim:
>>
>>         private static immutable ArrayPool s_shared;
>>
>>         shared static this() {
>>             s_shared = cast(immutable)new ConfigurableArrayPool();
>>         }
>
> Evet bu çalıştı.

D'de 'static' değişkenin ilk değerinin derleme zamanında hesaplanması gerekiyor. (Bu, C ve C++'tan farklı: Orada yerel değişken ilk kullanıldığında ilklenir ve bunun hesabını derleyicinin kodları tutar.)

> static this() {} ile direkt yanında atamanın neredeyse
> aynı olduğunu düşünüyordum.

'static this' her thread için işletiliyor, 'shared static this' ise her program için (mantıken ana thread tarafından işletiliyordur.)

Dikkat etmişsindir, öyle bir blok içinde 'immutable' değişkene atama yapılabiliyor. D böyle blokların ilklemek için kullanıldığını kabul ediyor.

Ali

December 16, 2022

On Thursday, 15 December 2022 at 17:37:34 UTC, Can Alpay Çiftci wrote:

>

Esenlikler

D'de neleri anımsıyorum diye bakmak için Dotnet kütüphanesinde var olan çöp toplayacıdaki baskıyı azaltmak için kullanılar array pool'u D'de de gerçekleştireyim istedim.

Sanırım çalışır işe yarabilir durumda. En azından öyle umuyorum.

Ancak // private static immutable ArrayPool s_shared = new ConfigurableArrayPool();
yorum satırını sildiğimdeki hatanın mantığını anlayamadım.

Öncelikle kod için teşekkürler, ne zamandır böyle lezzetli şeyleri ne yabancı forumda hele burada (benimkiler dahil) hiç görmüyoruz. Bir örnek daha var aslında: Ali hocanın cached() projesi. O kodu da okumak çok lezzetliydi...

Kodu tersten okumaya başladım ve statik olan Utilities'deki getMaxSizeForBucket() ile reserve edilen en fazla buketin değerini ve üssü şekilde işlevlerle tespit edildiğini öğrendim. Kısaca maxSize'ı değiştirmediğimiz müddetçe, değeri 16'dan az olamıyor ama daha fazla yapmak elimizde.

Tabi neden immutable yapmak istediğini anlayamazsam da yorumları koda dahil ettiğimde derleme hatasıyla karşılaştım. Hoş, program çalışsa da nedenini bilmediğim bir hatadan dolayı (son satırdaki yorum) hafızanın tam temizlenememesi gibi bir sorunumuz daha var sanki? Ama hatayı bulabilmek için çıktıyı daha anlamı hale getirmeliydim ve şöyle bir örnek yazdım:

import std.stdio;
import array_pool;

struct OLASILIKLAR {
  uint A;
  Para B;
}

enum Para { Yazı, Tura, Dik }
enum test = 8; // 8 x 64 = 512 para atışı

void main()
{
  //static immutable
  auto s_shared = new ArrayPool!OLASILIKLAR;
  foreach (_; 1..test)
      test64!OLASILIKLAR;
  "-bitti-".writeln;
}

auto test64(T)(size_t capacity = 64)
{
  import std.random;
  auto APS = new ArrayPool!T;
  auto mem = APS.rent(capacity);
  for(auto i = 0; i < mem.length; i++)
  {
    mem[i] = OLASILIKLAR ();
    mem[i].A = i + 1;
    mem[i].B = uniform!Para;
  }

  foreach (item; mem)
  {
    item.A.writeln(": ", item.B);
  }
  APS.returnToPool(mem); /* Nedense hep bu hata:
   Aborting from src/core/sync/mutex.d(149) Error: pthread_mutex_destroy failed
  */
}

Tabi kodu biraz sadeleştirmek adına tüm public'leri (çünkü D'de her şey public) abstract'ı kaldırdım. Bu, bana OLASILIKLAR yapısını daha kolay bildirmemi sağladı. Yani şablonu asıl ArrayPool'a (önceki ismi başkaydı) yedirdim.

İş yerinde vakit bulabilirsem kodu biraz daha okumaya çalışacağım ama belli ki Mutex immutable'a izin vermiyor. Peki bir soru, nesneler immutable olmadan şu şekilde çalışması yeterli midir?

>

~ dmd main.d -ofmain.out array_pool
~ ./main.out
1: Tura
2: Dik
3: Yazı
4: Tura
5: Dik
6: Tura
7: Yazı
8: Yazı
...

December 16, 2022

On Thursday, 15 December 2022 at 17:37:34 UTC, Can Alpay Çiftci wrote:

>
module array_pool;
template MyTemplate(T)
{
    public abstract class ArrayPool
    {
//... MAIN ...//
	auto _buckets = MyTemplate!(MyClass).ArrayPool.create;
//...

Küçük bir öneri, template() ile şablon parametrelerini yukardaki gibi açık bir şekilde sarmalayacaksan içinde aynı isimde bir işlev olmasını veya gerek duymuyorsan içindeki nesneye kaynaştırarak kısa biçimde yazmayı deneyebilirsin.

Başarılar...

December 16, 2022

On Thursday, 15 December 2022 at 23:21:13 UTC, Ali Çehreli wrote:

>

Evet, hiçbir değişiklik yapmadan patlıyor. Ben Linux üzerindeyim. Birazdan anlamaya çalışırım. Buldum:

            finally
            {
                if (lockTaken)
                {
                    mutex.tryLock_nothrow();
                }
            }

unlock_nothrow olacakmış.

Fakat tryLock_nothrow'un döndürdüğü değeri doğru kullandığından emin misin? (Belgesi pek açıklayıcı değil.) 'false' döndürdüğünde işine devam etme hakkın oluyor mu? Çünkü kilitle(ye)mediğinde 'false' döndürüyormuş.

Yanlış kullanıyorum. Belge açıklayacı olmasa da bu konuda belge değil işlev adından bile çıkacak bir nenmiş aslında. Benim hatam. Kiliti alamadığında alana kadar spin atan(threadi boşta bekleten) bir method varsa onu kullanmak isterdim. Bu method o konuda ne kadar istekli bilmiyorum. Bekliyor mu zaman aşımı hatası atıyor mu?

Burada nothrow methodların olup error throw etmesi garip. Keşke onun yerine throw olsa olanları methodda bildirsek.(Javada şimdi kontrol ettim Exception yakalanmaz ise throws diye belirtmek gerekiyor. Error isteğe bağlı.)

On Friday, 16 December 2022 at 05:04:23 UTC, Salih Dincer wrote:

>

Tabi neden immutable yapmak istediğini anlayamazsam da yorumları koda dahil ettiğimde derleme hatasıyla karşılaştım. Hoş, program çalışsa da nedenini bilmediğim bir hatadan dolayı (son satırdaki yorum) hafızanın tam temizlenememesi gibi bir sorunumuz daha var sanki? Ama hatayı bulabilmek için çıktıyı daha anlamı hale getirmeliydim ve şöyle bir örnek yazdım:

D dili için konuşmuyorum. D dili için konuşsam immutable yapmamın bir amacı da bu kod için shared olması olurdu. Aslında readonly yapmak istemiştim. Bunun nedeni yanlışlıkla başka değişkene erişmesine engel olmak ve de readonly olması aslında derleyiciye bazı durumlarda bazı eniyileştirme olanakları sağlayabiliyor. Genel olarak ilke olarak yaptığım iş acil değilse en dar kapsamda oluşturup genişletmeyi seviyorum. Örneğin buradan ayrı olarak genelde private ile ilerler sonra üzerine public olmalı mı biçiminde düşünürüm. Aciliyeti var ise de tam tersini seviyorum

auto test64(T)(size_t capacity = 64)

kod için dönüş türü void ise auto kullanmama taraftarı olurdum ben. Burada böyle bir düşünsel birlik var mı?

On Friday, 16 December 2022 at 05:04:23 UTC, Salih Dincer wrote:

>

İş yerinde vakit bulabilirsem kodu biraz daha okumaya çalışacağım ama belli ki Mutex immutable'a izin vermiyor. Peki bir soru, nesneler immutable olmadan şu şekilde çalışması yeterli midir?
Programın çalışması yeterli değil. Aynı belleği dönüp dönmediği çok önemli. Ben baktığımda aynı bellek adresi dönüyor. Senin örneğini çalıştırmadım ama her zaman yeni bir arraypool oluşturuyorsun sanki. Bu senaryoda yararı değil zararı olur gibi.

Abstract methodların olmasının nedeni bunu gerçekleştirecek başka sınıflar da olacak. Örneğin işparçacığı özelinde veri saklayacak biçiminde.

On Friday, 16 December 2022 at 15:44:30 UTC, Salih Dincer wrote:

>

Küçük bir öneri, template() ile şablon parametrelerini yukardaki gibi açık bir şekilde sarmalayacaksan içinde aynı isimde bir işlev olmasını veya gerek duymuyorsan içindeki nesneye kaynaştırarak kısa biçimde yazmayı deneyebilirsin.

İnanır mısın diğer örnekler hep bu biçimde olduğu için bunun nasıl yapıldığını öğrenmek için yaptım. Yanlış sözdizimi kullandığımda D bana yeterince yardımcı olmadı ve sanırım en çok kodun bu kısmı için uğraştım :-D

December 16, 2022
On 12/16/22 09:42, Can Alpay Çiftci wrote:

> Burada nothrow methodların olup error throw etmesi garip.

O, D'nin kendine özgü kararlarından birisidir. :)

> Keşke onun
> yerine throw olsa olanları methodda bildirsek.(Javada şimdi kontrol
> ettim Exception yakalanmaz ise throws diye belirtmek gerekiyor. Error
> isteğe bağlı.)

Ona benzer şeyleri C++ da denedi ama buldukları çözümler tam çözüm olamadı. Sorun, o 'throws' bildirimlerinin işlev arayüzlerinin parçaları olmamalarında.

'throws' olan bir işlevden öyle olduğunu bildirmeyen işlev çağırabiliyorsun. (ABI uyuşmazlığı olmuyor.) Çağırabildiğin işlev hata attığında da çalışma zamanında göçüyorsun.

> kod için dönüş türü void ise auto kullanmama taraftarı olurdum ben.
> Burada böyle bir düşünsel birlik var mı?

Kesin bir karar yok: auto'nun yararları yanında zararlarının da farkındayız. :/

> İnanır mısın diğer örnekler hep bu biçimde olduğu için bunun nasıl
> yapıldığını öğrenmek için yaptım. Yanlış sözdizimi kullandığımda D bana
> yeterince yardımcı olmadı ve sanırım en çok kodun bu kısmı için uğraştım
> :-D

- Sarmalayan template'ı kaldır ve (T)'yi içindeki türlere ver.

- Gereken bir kaç yerde örneğin ConfigurableArrayPool!T yaz.

Şunun gibi:

module array_pool;

@safe:

// (T) ekledik:
public abstract class ArrayPool(T)
{
// ...
    @property
        public static auto create()
    {
        // !T ekledik:
        return new ConfigurableArrayPool!T();
    }

    // Onu başka yerde de yaptık; kolaylık için alias kullanılabilir
    // ...
}


// Hem (T) hem !T ekledik:
final public class ConfigurableArrayPool(T) : ArrayPool!T
{
// ...
}

// ...

int main(string[] args)
{
    // MyTemplate'i attık:
    auto _buckets = ArrayPool!MyClass.create;
    // ...
}

Ali

December 16, 2022
On Friday, 16 December 2022 at 18:45:23 UTC, Ali Çehreli wrote:

> Ona benzer şeyleri C++ da denedi ama buldukları çözümler tam çözüm olamadı. Sorun, o 'throws' bildirimlerinin işlev arayüzlerinin parçaları olmamalarında.

Bu imzaya dahil olmamaları anlamında mı? Bana derleme zamanı denetlenmesi yeterli gibi geldi. C++da bilmediğimden kafamdaki yapıdaki oradaki gibi bir kısıtlılık var mı bilemiyorum. Javadaki throws'u sevmeyen bir topluluk var ancak belgelenmesi açısından bile ben çok yararlı buluyorum. Orada istisnadan türetilerek atılan her istisnayı(RuntimeExceptiondan türetilenler istisna :-P ) method tanımında belirtmek zorunluluğu var. Ve method içinde kullanılan method istisna fırlatıyor ise ya onu yakalamak ya da tanıma eklemek zorunlu.

Gerçekleştirim durumu: https://github.com/dlang/dmd/pull/12934

Bu arada şu biçimde bir DIP varmış: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md Bununla ilgili bir dil tasarımı düşüncesi var ancak nothrow'un karşıtı olarak sanırım. İşlevin ne attığını belirtemiyoruz ve de istisna fırlatırken dil istisna tipini bildirmekte bizi zorunlu tutmuyor. Hatta throw diye belirtme zorunlulu yok.

> - Sarmalayan template'ı kaldır ve (T)'yi içindeki türlere ver.
>
> - Gereken bir kaç yerde örneğin ConfigurableArrayPool!T yaz.
>
> Şunun gibi:
>

Burada anlatım bozukluğu yapmışım. Bu örnekteki zaten benim çalıştığım dillerdeki düzen. Elim ister istemez ona gidyor. Kodu yolladığım, yani ilk iletideki duruma getirmek zamanımı aldı :-)

December 16, 2022
On 12/16/22 13:01, Can Alpay Çiftci wrote:

> Bu imzaya dahil olmamaları anlamında mı? Bana derleme zamanı
> denetlenmesi yeterli gibi geldi.

İmzaya dahil olmayınca olanaksız. C++'ın başaramadığını şurada görüyoruz:

  https://cplusplus.com/doc/tutorial/exceptions/

"Older code may contain dynamic exception specifications. They
are now deprecated in C++, but still supported."

> belgelenmesi açısından bile ben çok yararlı buluyorum.

Java denetlediği için kullanışlı olmalı. Yoksa, C++'ta denetlenemediğinde belgesinin de anlamı kalmaz; kod değişir belge geri kalır.

> ancak nothrow'un karşıtı olarak sanırım.

Evet. O, bu konuyla tam ilgili değil. Orada, D'nin bazı attribute'larından kaçış olmamasını gidermeye çalışıyorlar. Örneğin, iki işlevi 'private' yapmak isteyeyim:

private:
  void foo();
  int bar();

// Burada "private bitti" diyemiyoruz.

'public' yazsam yanlış olur çünkü belki en başka 'public' değildi. (?) Dolayısıyla her attribute'ün bir no'lusunun da olması isteniyor.

> İşlevin ne attığını belirtemiyoruz ve de istisna
> fırlatırken dil istisna tipini bildirmekte bizi zorunlu tutmuyor. Hatta
> throw diye belirtme zorunlulu yok.

Mutluyum çünkü hiç sıkıntısını çekmedim. :)

Ali