Broofa'nın cevabı gerçekten kaygan, etkileyici - gerçekten akıllı, gerçekten ... rfc4122 uyumlu, biraz okunabilir ve kompakt. Müthiş!
O düzenli ifade bakıyoruz Ama, eğer o pek replace()
geri aramalar toString()
'ın ve Math.random()
(o sadece sonucun 4 bit kullanarak ve dinlenme israf oluyor) işlev çağrıları, performans hakkında merak başlayabilir. Gerçekten de, joelpt, genel GUID hızı için RFC'yi atmaya bile karar verdi generateQuickGUID
.
Ancak, hız ve RFC uyumluluğu alabilir miyiz ? Evet dedim! Okunabilirliği koruyabilir miyiz? Şey ... Pek değil, ama takip ederseniz kolay.
Ama önce, broofa, guid
(kabul edilen cevap) ve rfc uyumlu olmayanlarla karşılaştırıldığında sonuçlarım generateQuickGuid
:
Desktop Android
broofa: 1617ms 12869ms
e1: 636ms 5778ms
e2: 606ms 4754ms
e3: 364ms 3003ms
e4: 329ms 2015ms
e5: 147ms 1156ms
e6: 146ms 1035ms
e7: 105ms 726ms
guid: 962ms 10762ms
generateQuickGuid: 292ms 2961ms
- Note: 500k iterations, results will vary by browser/cpu.
6. optimizasyon yinelememle, en popüler cevabı 12X'in üzerinde, 9X'in üzerinde kabul edilen cevabı ve 2-3X'in hızlı uyumlu olmayan cevabını yendim . Ve hala rfc4122 uyumluyum.
Nasıl? Tüm kaynağı http://jsfiddle.net/jcward/7hyaC/3/ ve http://jsperf.com/uuid-generator-opt/4 üzerine koydum
Bir açıklama için, broofa'nın koduyla başlayalım:
function broofa() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
console.log(broofa())
Bu nedenle x
, y
rastgele verilerle (en iyi 2 biti 10
RFC spesifikasyonuna göre zorlamak hariç) herhangi bir rastgele onaltılık basamakla değiştirilir ve normal ifade -
veya 4
karakterleriyle eşleşmez , bu nedenle onlarla uğraşması gerekmez. Çok, çok kaygan.
Bilmeniz gereken ilk şey, düzenli çağrılar gibi işlev çağrılarının pahalı olmasıdır (her ne kadar sadece 1 kullanıyorsa da, her maç için bir tane olmak üzere 32 geri arama vardır ve 32. geri çağırmanın her birinde Math.random () ve v olarak adlandırılır. toString (16)).
Performansa giden ilk adım RegEx ve geri çağrı işlevlerini ortadan kaldırmak ve bunun yerine basit bir döngü kullanmaktır. Bu , broofa'nın yapmadığı -
ve ve 4
karakterleriyle uğraşmamız gerektiği anlamına gelir . Ayrıca, kaygan String şablonu mimarisini korumak için String Array dizinini kullanabileceğimizi unutmayın:
function e1() {
var u='',i=0;
while(i++<36) {
var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:v.toString(16)
}
return u;
}
console.log(e1())
Temelde, aynı iç mantığı, biz kontrol hariç -
veya 4
ve (yerine while döngüsü kullanılmasının replace()
geri aramaları) bize neredeyse 3X iyileşme alır!
Bir sonraki adım masaüstünde küçük bir adımdır, ancak mobil cihazlarda iyi bir fark yaratır. Daha az Math.random () çağrısı yapalım ve her yinelemeyi değiştiren rastgele bir arabellekle% 87'sini atmak yerine tüm bu rastgele bitleri kullanalım. Ayrıca, yardımcı olması durumunda bu şablon tanımını döngüden çıkaralım:
function e2() {
var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;
while(i++<36) {
var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
}
return u
}
console.log(e2())
Bu, platforma bağlı olarak bizi% 10-30 tasarruf sağlıyor. Fena değil. Ancak bir sonraki büyük adım, bir optimizasyon klasiğiyle toString işlev çağrılarından tamamen kurtulur - arama tablosu. Basit bir 16 elemanlı arama tablosu, toString (16) işini çok daha kısa sürede gerçekleştirir:
function e3() {
var h='0123456789abcdef';
var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
/* same as e4() below */
}
function e4() {
var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
var u='',i=0,rb=Math.random()*0xffffffff|0;
while(i++<36) {
var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
}
return u
}
console.log(e4())
Bir sonraki optimizasyon başka bir klasik. Her döngü yinelemesinde yalnızca 4 bit çıktı işlediğimiz için, döngü sayısını yarıya indirelim ve her yinelemeyi 8 bit işleyelim. RFC uyumlu bit konumlarını hala ele almamız gerektiğinden bu zor, ancak çok zor değil. Daha sonra 0x00 - 0xff'yi saklamak için daha büyük bir arama tablosu (16x16 veya 256) yapmamız gerekiyor ve e5 () işlevinin dışında yalnızca bir kez oluşturuyoruz.
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
var u='',i=0,rb=Math.random()*0xffffffff|0;
while(i++<20) {
var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
}
return u
}
console.log(e5())
Hala 256-element LUT kullanarak, bir seferde 16 bit işleyen bir e6 () denedim ve optimizasyon azalan dönüşlerini gösterdi. Daha az yineleme olmasına rağmen, iç mantık artan işleme ile karmaşıktı ve aynı şeyi masaüstünde gerçekleştirdi ve mobil cihazlarda yalnızca ~% 10 daha hızlıydı.
Uygulanacak son optimizasyon tekniği - döngüyü açın. Sabit sayıda döngü yaptığımız için, bunları teknik olarak elle yazabiliriz. Bunu bir kez yeniden atamaya devam ettiğim tek bir rastgele değişken r ile denedim ve performans tanklandı. Ancak dört değişkenin önüne rastgele veriler atandıktan sonra arama tablosunu kullanarak ve uygun RFC bitlerini uygulayarak bu sürüm hepsini sigara içiyor:
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
var d0 = Math.random()*0xffffffff|0;
var d1 = Math.random()*0xffffffff|0;
var d2 = Math.random()*0xffffffff|0;
var d3 = Math.random()*0xffffffff|0;
return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}
console.log(e7())
Değiştirilmiş: http://jcward.com/UUID.js -UUID.generate()
Komik olan şey, 16 bayt rasgele veri oluşturmak kolay bir parçadır. Tüm hile, RFC uyumluluğu ile String biçiminde ifade ediyor ve 16 bayt rastgele veri, bir kaydedilmemiş döngü ve arama tablosu ile en sıkı şekilde gerçekleştiriliyor.
Umarım mantığım doğrudur - bu tür sıkıcı bit işlerinde bir hata yapmak çok kolaydır. Ama çıktılar bana iyi geliyor. Umarım kod optimizasyonu ile bu deli sürüş zevk!
Tavsiyem: Temel amacım potansiyel optimizasyon stratejilerini göstermek ve öğretmekti. Diğer cevaplar, iyi UUID'ler oluşturmak için önemli olan çarpışmalar ve gerçekten rastgele sayılar gibi önemli konuları kapsar.