2011-09-07 66 views
1

所以我有一种方法可以生成条码和带有该条码的标签。我们注意到,当多个用户同时生成条形码时,他们都会得到相同的文件。我使用的是ASP.NET,我正在主持应用程序和文件在内部服务器上。为什么这种方法向不同的用户吐出相同的结果

public void trickylabel(string fnsku, string title) 
{ 
    Random random = new Random(); 
    int randomNumber = random.Next(0, 100000); 

    //Set barcode properties... 

    code.parse(fnsku); // Text 

    BCGDrawing drawing = new BCGDrawing(this.Server.MapPath("~") + "image"+ randomNumber.ToString() +".png", color_white); 
    drawing.setBarcode(code); 
    drawing.draw(); 

    // Draw (or save) the image into PNG format. 
    Response.ContentType = "image/png"; 
    drawing.finish(ImageFormat.Png); 

    Document doc = new Document(new iTextSharp.text.Rectangle(200f, 75f), 20F, 10F, 10F, 1F); 
    PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(Request.PhysicalApplicationPath + 
     "\\"+randomNumber.ToString()+".pdf", FileMode.Create)); 

    doc.Open(); 

    iTextSharp.text.Image png = iTextSharp.text.Image.GetInstance(this.Server.MapPath("~") + "image" + randomNumber.ToString() +".png"); 

    doc.Add(png); 

    //Sets pdf properties... 

    doc.Add(new Paragraph(title, times)); 
    PdfAction action = new PdfAction(PdfAction.PRINTDIALOG); 
    writer.SetOpenAction(action); 
    doc.Close(); 

    Response.ContentType = "application/pdf"; 
    Response.AppendHeader("Content-Disposition", "attachment; filename=labels.pdf"); 
    Response.TransmitFile(Server.MapPath("~/"+randomNumber.ToString()+".pdf")); 

} 

回答

4

的问题是在这里:

Random random = new Random(); 
int randomNumber = random.Next(0, 100000); 

Random类产生伪随机序列,这是基于一些初始值,称为种子。如果两个Random实例用相同的种子初始化,它们将产生相同的数字序列。

当使用无参数构造函数创建Random时,将根据当前系统时间创建Seed。如果您运行一个创建Random类实例的循环,您将会注意到random.Next()值每秒只更改几次(每16ms一次)。

要(不过由于使用的是ASP.Net你需要确保random.Next()的调用以线程安全的方式被执行)避免这种情况,你应该重用初始化随机实例。然后你的访问者会得到不同的值,每个新的random.Next(...)调用。

或者Random有一个构造函数,允许手动设置初始的Seed值。因此,您可以创建自己的为用户创建独特种子的算法。

UPDATE线程安全的Randomizer实现。 获取在装配负载上初始化。

使用方法:只需更换random.Next(0, 100000);Randomizer.Next(0, 100000);

public static class Randomizer 
{ 
    private static Random rnd; 
    static Randomizer() 
    { 
     rnd = new Random(); 
     rndlock = new object(); 
    } 

    private static object rndlock; 
    public static int Next(int minValue, int maxValue) 
    { 
     lock(rndlock) 
     { 
      return rnd.Next(minValue, maxValue); 
     } 
    } 
} 

UPDATE在线程安全和不可预知的结果

如上所述,随机生成的伪随机序列。这意味着这个序列中的每个整数都知道前一个和后一个数字。这意味着经过一定次数的通话后,这些号码将开始重复。 Random.Next()算法旨在最大化此序列中唯一项目的数量。

那么,在这种情况下“不可预知”是什么意思?当多个线程同时使用相同的变量时,该算法的逻辑将被破坏。在最好的情况下,这会使更多的序列出现相同的数字。在最糟糕的情况下Random.Next()starts to produce zero values on each call没有任何恢复的机会。

更多关于System.Random的信息在MSDN

+1

FYI ...随机()被初始化Environment.TickCount –

+0

@保罗墙:谢谢!我想知道为什么DateTime.Now.Ticks比Random的种子更频繁地变化。在我的机器上,这个值每16毫秒只改变一次,所以你不能依靠两个连续访问者将有不同的Datetime.Now.Ticks的事实。 16毫秒是获得重复结果的很长一段时间。 – Artemix

+1

@Artemix:关于*“...例如,您可以将Random实例存储在某个静态成员”*中。 **不要这样做!**'随机'不是线程安全的;如果您将一个实例存储为静态,那么除非您自己实施某种类型的同步,否则您将得到更奇怪的结果(即损坏)结果。 – LukeH

0

如果请求在同一时间开始,那么生成的随机数可能会彼此相同。在不提供种子值的情况下,Random构造函数根据系统时钟获取它的种子,因此两个实例可能产生相同的一组随机值(它们不是随机的,它们是伪随机的)。

文档在这里 - http://msdn.microsoft.com/en-us/library/system.random.aspx

请尝试将随机实例类的静态成员,有你的方法只是调用。接下来该部件上。

0

您是否需要将pdf保存到磁盘?

我建议将png图像和pdf文档保存为MemoryStream。 这可能也会导致更好的性能,因为磁盘访问较少。

public void trickylabel(string fnsku, string title) 
{ 
    //Set barcode properties... 

    code.parse(fnsku); // Text 

    BCGDrawing drawing = new BCGDrawing(color_white); 
    drawing.setBarcode(code); 
    drawing.draw(); 

    // Draw (or save) the image into PNG format. 

    using (var imageStream = new MemoryStream()) 
    { 
     drawing.finish(ImageFormat.Png, imageStream); 

     using (var result = new MemoryStream()) 
     { 
      Document doc = new Document(new iTextSharp.text.Rectangle(200f, 75f), 20F, 10F, 10F, 1F); 
      PdfWriter writer = PdfWriter.GetInstance(doc, result); 

      doc.Open(); 

      var png = iTextSharp.text.Image.GetInstance(System.Drawing.Image.FromStream(imageStream), ImageFormat.Png); 
      doc.Add(png); 

      //Sets pdf properties... 

      doc.Add(new Paragraph(title, times)); 
      PdfAction action = new PdfAction(PdfAction.PRINTDIALOG); 
      writer.SetOpenAction(action); 
      doc.Close(); 

      Response.ContentType = "application/pdf"; 
      Response.AppendHeader("Content-Disposition", "attachment; filename=labels.pdf"); 
      Response.BinaryWrite(result.ToArray()); 
     } 
    } 
} 
1

或者只是使用NewGuid Method

+0

我同意,100,000似乎有很多“独特性”的空间,但它与GUID的空间相比并不算什么 –

+0

@Chris Haas:然而,在这种情况下,将GUID限制为条形码ID可能会产生比普通Random.Next更多的不需要的匹配。 (0,100000)的用法。此外,如果您正在寻找替代随机数字源,您可能有兴趣使用RNGCryptoServiceProvider类:http://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.aspx – Artemix

+0

@Artemix,I同意永远不应该修剪GUID或仅将其部分。由于需求是创建一个唯一的东西,而一个GUID只需要32个字符(或者如果你使用类似'ShortGuid'的更少),这似乎是一个合理的选择。随机性和独特性是非常不同的,这个项目对我来说没有任何关于“随机”的说法。 –

相关问题