अन्य जवाबों की समीक्षा करने और CodeInChaos की टिप्पणियों पर विचार करने के बाद, CodeInChaos के साथ अभी भी पक्षपाती (हालांकि कम) जवाब है, मैंने सोचा कि अंतिम अंतिम कट और पेस्ट समाधान की आवश्यकता थी। इसलिए अपने जवाब को अपडेट करते हुए मैंने सभी बाहर जाने का फैसला किया।
इस कोड के अद्यतित संस्करण के लिए, कृपया Bitbucket पर नई Hg रिपॉजिटरी पर जाएँ: https://bitbucket.org/merarischroeder/secureswiftrandom । मैं आपको कोड की प्रतिलिपि बनाने और उससे कोड पेस्ट करने की सलाह देता हूं: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdfcffc7496ea/Code/Alivate.SolidSwiftRwift.iftRiftRiftRift.ift (सुनिश्चित करें कि आप क्लिक करें कच्चे बटन को कॉपी करना आसान है और सुनिश्चित करें कि आपके पास नवीनतम संस्करण है, मुझे लगता है कि यह लिंक कोड के एक विशिष्ट संस्करण पर जाता है, नवीनतम नहीं)।
अपडेट किए गए नोट:
- कुछ अन्य उत्तरों से संबंधित - यदि आप आउटपुट की लंबाई जानते हैं, तो आपको StringBuilder की आवश्यकता नहीं है, और ToCharArray का उपयोग करते समय, यह सरणी को बनाता है और भरता है (आपको पहले खाली सरणी बनाने की आवश्यकता नहीं है)
- कुछ अन्य उत्तरों से संबंधित - आपको प्रदर्शन के लिए एक समय पर एक होने के बजाय, नेक्स्टबाइट्स का उपयोग करना चाहिए
- तकनीकी रूप से आप तेजी से पहुंच के लिए बाइट सरणी को पिन कर सकते हैं .. यह आमतौर पर इसके लायक है जब आपका बाइट सरणी पर 6-8 से अधिक बार पुनरावृति करता है। (यहाँ नहीं किया गया)
- सर्वश्रेष्ठ यादृच्छिकता के लिए RNGCryptoServiceProvider का उपयोग
- यादृच्छिक डेटा के 1 एमबी बफर के कैशिंग का उपयोग - बेंचमार्किंग से पता चलता है कि कैश्ड सिंगल बाइट्स एक्सेस स्पीड ~ 1000x तेज़ है - अनचाहे के लिए 1 एमबी बनाम 989ms पर 9ms ले रही है।
- मेरी नई कक्षा के भीतर पूर्वाग्रह क्षेत्र का अनुकूलित अस्वीकृति ।
प्रश्न का अंतिम समाधान:
static char[] charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
लेकिन आपको मेरी नई (अप्रयुक्त) श्रेणी की आवश्यकता है:
/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
static int lastPosition = 0;
static int remaining = 0;
/// <summary>
/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
/// </summary>
/// <param name="buffer"></param>
public static void DirectGetBytes(byte[] buffer)
{
using (var r = new RNGCryptoServiceProvider())
{
r.GetBytes(buffer);
}
}
/// <summary>
/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
/// </summary>
/// <param name="buffer"></param>
public static void GetBytes(byte[] buffer)
{
if (buffer.Length > byteCache.Length)
{
DirectGetBytes(buffer);
return;
}
lock (byteCache)
{
if (buffer.Length > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
}
}
/// <summary>
/// Return a single byte from the cache of random data.
/// </summary>
/// <returns></returns>
public static byte GetByte()
{
lock (byteCache)
{
return UnsafeGetByte();
}
}
/// <summary>
/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
/// </summary>
/// <returns></returns>
static byte UnsafeGetByte()
{
if (1 > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
lastPosition++;
remaining--;
return byteCache[lastPosition - 1];
}
/// <summary>
/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
public static void GetBytesWithMax(byte[] buffer, byte max)
{
if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
{
DirectGetBytes(buffer);
lock (byteCache)
{
UnsafeCheckBytesMax(buffer, max);
}
}
else
{
lock (byteCache)
{
if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
DirectGetBytes(byteCache);
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
UnsafeCheckBytesMax(buffer, max);
}
}
}
/// <summary>
/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
static void UnsafeCheckBytesMax(byte[] buffer, byte max)
{
for (int i = 0; i < buffer.Length; i++)
{
while (buffer[i] >= max)
buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
}
}
}
इतिहास के लिए - इस उत्तर के लिए मेरा पुराना समाधान, रैंडम ऑब्जेक्ट का उपयोग किया गया है:
private static char[] charSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
lock (rGen) //~20-50ns
{
rGen.NextBytes(rBytes);
for (int i = 0; i < Length; i++)
{
while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i] = rGen.NextByte();
rName[i] = charSet[rBytes[i] % charSet.Length];
}
}
return new string(rName);
}
प्रदर्शन:
- सिक्योर फ़र्स्टग्रैंड - पहला एकल रन = ~ 9-33 मी । अतीन्द्रिय। चल रहा है : 10,000 से अधिक पुनरावृत्तियों पर 5ms (कभी-कभी यह 13ms तक जाता है), एक एकल औसत चलना = 1.5 माइक्रोसेकंड के साथ।। नोट: आम तौर पर 2 की आवश्यकता होती है, लेकिन कभी-कभी 8 कैश रीफ्रेश तक - यह निर्भर करता है कि कितने सिंगल बाइट्स पूर्वाग्रह क्षेत्र से अधिक हैं
- रैंडम - पहला एकल रन = ~ 0-1ms । अतीन्द्रिय। चल रहा है : 10,000 से अधिक पुनरावृत्तियों पर 5ms । एक एकल औसत चलना = .5 माइक्रोसेकंड के साथ। । उसी गति के बारे में।
यह भी देखें:
ये लिंक एक और दृष्टिकोण हैं। बफ़रिंग को इस नए कोड बेस में जोड़ा जा सकता है, लेकिन सबसे महत्वपूर्ण पूर्वाग्रह को हटाने के लिए अलग-अलग दृष्टिकोणों की खोज कर रहा था, और गति और पेशेवरों / विपक्ष को बेंचमार्क कर रहा था।