2

我目前正在处理一个必须连续生成大约 16000 封电子邮件的批次(时事通讯)。

不管它是不是垃圾邮件,我的问题是关于我如何生成这些电子邮件。

消息中的某些字段必须替换为自定义值(日期、用户名等)。

由于某些截止日期和代码可重用性的原因,我的模板是一个 HTML 文件,其中包含一些“_FIELDNAME”字段,可以通过正则表达式轻松发现:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
...
<body>
<p>Hi _NAME, _DATE newsletter.</p>
</body>
...

该文件大约有 1000 行,因此在加载时它是一个相当大的字符串。

首先,我在一个字符串中加载一次 HTML 文件模板:

string template = File.ReadAllText(@"Template/newsletter.html");

替换功能如下所示:

return new StringBuilder(template)
.Replace("_DATE", profileConfig.SelectedMonth.ToString("MMMM yyyy"))
.Replace("_NAME", profileConfig.Name)
.ToString();

问题是内存消耗在每次迭代中都会略有增加。1000 次迭代大约 50MB,这是由于我的替换功能(我试图评论它并且内存泄漏消失了)。

如何替换模板中的许多字段 (~50) 而不会溢出我的 16000 次迭代的内存?我尝试了几件事,比如使用正则表达式(但它使用字符串)或临时文件,但两者都不满意。

在此先感谢您的帮助。

4

3 回答 3

3

如果您可以将 , 等替换_DATE_NAME, 等{0}{1}您可以尝试string.Format()

模板将变为:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
...
<body>
<p>Hi {0}, {1} newsletter.</p>
</body>
...

代码如下所示:

return string.Format(template, 
        profileConfig.SelectedMonth.ToString("MMMM yyyy"), 
        profileConfig.Name
    );

你实际上根本不需要经历StringBuilder。如果您File.ReadAllLines()只在包含令牌的行中交换值,您将极大地受益于速度(并且可能在资源使用方面)。

更新为了强制使用string.Format(string format, params object[] args)重载,您可能必须将所有参数放入一个集合中。

以下内容应该使此解决方案适合您(我测试了多达 1000 个参数,它既有效非常快)。

List<string> tokenValues = new List<string> 
{ 
    profileConfig.SelectedMonth.ToString("MMMM yyyy"), 
    profileConfig.Name, 
    <follow with your other values>
};
return string.Format(template, tokenValues.ToArray()); //.ToArray() is mandatory
于 2012-07-31T13:24:48.440 回答
1
    var patterns = new Dictionary<string, string>();
    patterns["_Date"] = profileConfig.SelectedMonth.ToString("MMMM yyyy");
    patterns["_Name"] = profileConfig.Name;

    var builder = new StringBuilder(template.Length);
    for (var i = 0; i < template.Length;)
    {
      var pattern = CompareAndFindPattern(template, i, patterns);
      if (pattern != null)
      {
        builder.Append(pattern.Value.Value);
        i += pattern.Value.Key.Length;
      }
      else
      {
        builder.Append(template[i]);
        i++;
      }
    }

  static KeyValuePair<string, string>? CompareAndFindPattern(string template, int index, Dictionary<string, string> patterns)
  {
    foreach (var pattern in patterns)
    {
      if (string.Compare(template, index, pattern.Key, 0, pattern.Key.Length) == 0)
        return pattern;
    }
    return null;
  }
于 2012-07-31T13:34:07.933 回答
0

在尝试了许多解决方案之后,我终于决定从头开始重新启动我的批次。

我现在使用适当的 XSLT 文件从 XML 配置生成 HTML。

内存消耗仍会随着时间的推移而增加,但现在变慢了。我猜垃圾收集器不想收集,因为我的电脑有 6GB RAM,没有其他巨大的进程可以运行。

于 2012-08-01T13:37:37.747 回答