ब्रूफा का जवाब बहुत चालाक है, वास्तव में - प्रभावशाली रूप से चतुर, वास्तव में ... rfc4122 आज्ञाकारी, कुछ पठनीय और कॉम्पैक्ट। बहुत बढ़िया!
लेकिन अगर आप उस नियमित अभिव्यक्ति को देख रहे हैं, तो वे कई replace()
कॉलबैक, toString()
और Math.random()
फ़ंक्शन कॉल (जहां वह केवल परिणाम के 4 बिट्स का उपयोग कर रहे हैं और बाकी को बर्बाद कर रहे हैं), आप प्रदर्शन के बारे में आश्चर्य करना शुरू कर सकते हैं। वास्तव में, joelpt ने भी सामान्य GUID गति के लिए RFC को टॉस करने का निर्णय लिया generateQuickGUID
।
लेकिन, क्या हम गति और आरएफसी अनुपालन प्राप्त कर सकते हैं ? मैं हां कहूंगा! क्या हम पठनीयता बनाए रख सकते हैं? खैर ... वास्तव में नहीं, लेकिन अगर आप साथ चलते हैं तो यह आसान है।
लेकिन पहले, मेरे परिणाम, ब्रूफो की तुलना में, guid
(स्वीकृत उत्तर), और गैर-आरएफसी-अनुपालन 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 पुनरावृत्ति द्वारा, मैंने सबसे लोकप्रिय उत्तर को 12X से अधिक , 9X से अधिक स्वीकार किए गए उत्तर और 2-3X द्वारा तेज़-गैर-अनुपालन उत्तर को हराया । और मैं अभी भी rfc4122 का अनुपालन कर रहा हूं।
में रुचि कैसे? मैं पर पूर्ण स्रोत डाल दिया http://jsfiddle.net/jcward/7hyaC/3/ और पर http://jsperf.com/uuid-generator-opt/4
एक स्पष्टीकरण के लिए, आइए ब्रूफ़ो के कोड से शुरू करें:
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())
इसलिए यह यादृच्छिक डेटा ( RFC कल्पना के अनुसार शीर्ष 2 बिट्स को छोड़कर) के x
साथ किसी भी यादृच्छिक हेक्स अंक के साथ बदलता है , और रेगेक्स या वर्णों से मेल नहीं खाता है , इसलिए उसे उनसे निपटने की ज़रूरत नहीं है। बहुत, बहुत चालाक।y
10
-
4
यह जानने के लिए पहली बात यह है कि फ़ंक्शन कॉल महंगे हैं, क्योंकि नियमित अभिव्यक्तियाँ हैं (हालांकि वह केवल 1 का उपयोग करता है, इसमें 32 कॉलबैक हैं, प्रत्येक मैच के लिए एक है, और प्रत्येक 32 कॉलबैक में यह Math.random () और v कहता है। toString (16))।
प्रदर्शन की ओर पहला कदम RegEx और इसके कॉलबैक कार्यों को समाप्त करना है और इसके बजाय एक साधारण लूप का उपयोग करना है। इसका मतलब यह है कि हमें पात्रों -
और 4
पात्रों के साथ व्यवहार करना होगा जबकि ब्रूफो ने नहीं किया। इसके अलावा, ध्यान दें कि हम स्ट्रिंग ऐरे इंडेक्सिंग का उपयोग उसकी स्लीक स्ट्रिंग टेम्प्लेट आर्किटेक्चर रखने के लिए कर सकते हैं:
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())
मूल रूप से, एक ही आंतरिक तर्क, सिवाय इसके कि हम जांच करते हैं , -
या 4
थोड़ी देर के लूप ( replace()
कॉलबैक के बजाय ) का उपयोग करने से हमें लगभग 3% सुधार मिलता है!
अगला कदम डेस्कटॉप पर एक छोटा सा है, लेकिन मोबाइल पर एक अच्छा अंतर बनाता है। आइए, कम से कम Math.random () कॉल करें और उन सभी यादृच्छिक बिट्स का उपयोग करें, जिनमें से 87% को फेंकने के बजाय एक यादृच्छिक बफर के साथ जो प्रत्येक पुनरावृत्ति को स्थानांतरित करता है। चलिए उस टेम्प्लेट की परिभाषा को लूप से बाहर करते हैं, बस अगर यह मदद करता है:
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())
यह प्लेटफॉर्म के आधार पर हमें 10-30% बचाता है। बुरा नहीं। लेकिन अगले बड़े कदम को पूरी तरह से एक अनुकूलन क्लासिक - लुक-अप टेबल के साथ स्टर्लिंग फ़ंक्शन कॉल से छुटकारा मिल जाता है। एक साधारण 16-तत्व लुकअप तालिका बहुत कम समय मेंString (16) का काम करेगी:
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())
अगला अनुकूलन एक और क्लासिक है। चूंकि हम प्रत्येक लूप पुनरावृत्ति में केवल 4-बिट आउटपुट को संभाल रहे हैं, चलो लूप की संख्या को आधे में काटते हैं और प्रत्येक पुनरावृत्ति को 8-बिट प्रोसेस करते हैं। यह मुश्किल है क्योंकि हमें अभी भी आरएफसी के अनुरूप पदों को संभालना है, लेकिन यह बहुत कठिन नहीं है। फिर हमें 0x00 - 0xff को स्टोर करने के लिए एक बड़ा लुकअप टेबल (16x16, या 256) बनाना होगा और हम इसे e5 () फ़ंक्शन के बाहर केवल एक बार बनाते हैं।
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())
मैंने एक ई 6 () की कोशिश की, जो एक समय में 16-बिट्स को संसाधित करता है, फिर भी 256-तत्व एलयूटी का उपयोग कर रहा है, और इसने अनुकूलन के कम रिटर्न को दिखाया। यद्यपि इसमें कम पुनरावृत्तियों थे, आंतरिक तर्क बढ़ी हुई प्रसंस्करण द्वारा जटिल था, और इसने डेस्कटॉप पर समान प्रदर्शन किया, और मोबाइल पर केवल ~ 10% तेजी से।
लागू करने के लिए अंतिम अनुकूलन तकनीक - लूप को अनियंत्रित करें। चूंकि हम कई बार निश्चित संख्या में लूपिंग करते हैं, इसलिए हम इसे तकनीकी रूप से हाथ से लिख सकते हैं। मैंने एक बार रैंडम वैरिएबल आर के साथ एक बार यह कोशिश की थी कि मैं फिर से असाइन करता रहूं, और परफॉर्मेंस टैंक हो जाए। लेकिन चार चर के साथ यादृच्छिक डेटा को सामने रखा, फिर लुकअप टेबल का उपयोग किया, और उचित RFC बिट्स को लागू किया, यह संस्करण उन सभी को धूम्रपान करता है:
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())
संशोधित: http://jcward.com/UUID.js -UUID.generate()
मजेदार बात यह है कि रैंडम डेटा के 16 बाइट्स बनाना आसान हिस्सा है। पूरी ट्रिक इसे RFC अनुपालन के साथ स्ट्रिंग प्रारूप में व्यक्त कर रही है, और यह यादृच्छिक डेटा के 16 बाइट्स, एक अनियंत्रित लूप और लुकअप टेबल के साथ सबसे कसकर पूरा किया गया है।
मुझे आशा है कि मेरा तर्क सही है - इस तरह के थकाऊ काम में गलती करना बहुत आसान है। लेकिन आउटपुट मुझे अच्छे लगते हैं। मुझे आशा है कि आपने कोड अनुकूलन के माध्यम से इस पागल सवारी का आनंद लिया!
सलाह दें: मेरा प्राथमिक लक्ष्य संभावित अनुकूलन रणनीतियों को दिखाना और सिखाना था। अन्य उत्तर महत्वपूर्ण विषयों जैसे टकराव और वास्तव में यादृच्छिक संख्या को कवर करते हैं, जो अच्छे यूयूआईडी उत्पन्न करने के लिए महत्वपूर्ण हैं।