【问题标题】:System.AggregateExeption while using Parallel.ForEach使用 Parallel.ForEach 时的 System.AggregateExeption
【发布时间】:2012-05-27 21:33:59
【问题描述】:

由于缺乏更好的选择,我正在构建这个网络爬虫来从他们的搜索中收集 Steam 个人资料 ID。

它应该作为服务运行,但我无法让它工作。如果我复制代码并将其作为控制台应用程序运行,它会完美运行。

我是 Windows 服务编程和使用并行任务的新手,所以如果还有其他完全关闭或效率低下的东西,请赐教,但手头的问题更重要。

我尝试使用 eventviewer 对其进行调试,但我对这些东西也很陌生,我发现它非常乏味,不知道要查找什么。

下面是在控制台应用程序中工作的代码,但不是作为 Windows 服务。为什么它只能在控制台应用程序中工作?

public partial class SSIDGatherer : ServiceBase
{
    EventLog log;
    Thread t;

    public SSIDGatherer()
    {
        InitializeComponent();

        if (!EventLog.SourceExists("SSIDGatherer"))
        {
            EventLog.CreateEventSource("SSIDGatherer", "SteamStats");
        }

        log = new EventLog();
        log.Source = "SSIDGatherer";
        log.Log = "SteamStats";
    }

    protected override void OnStart(string[] args)
    {
        ServicePointManager.UseNagleAlgorithm = true;
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.CheckCertificateRevocationList = true;
        ServicePointManager.DefaultConnectionLimit = 50;

        ThreadStart ts = new ThreadStart(Treading);

        try
        {
            t = new Thread(ts);
            t.Start();
        }
        catch (AggregateException agex)
        {
            string message = "";
            foreach (Exception ex in agex.InnerExceptions)
            {
                message += string.Format("Exception: {0} \n\nStack: {1}", ex.Message, ex.StackTrace);
            }

            log.WriteEntry(message, EventLogEntryType.Error);
        }
    }

    protected override void OnStop()
    {
        t.Abort();
    }

    private void Treading()
    {
        while (true)
        {
            //steam custom url allowed characters a-z 0-9 _ -
            string[] characters = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "_" };

            //for every combination you can do with 2 letters (which is minimum required for a player search)
            Parallel.ForEach(characters, characterX =>
            {
                Parallel.ForEach(characters, characterY =>
                            {
                                CrawlSteamIDs("http://steamcommunity.com/actions/Search?T=Account", characterX + characterY, 1);
                            });
            });
        }
    }

    private void CrawlSteamIDs(string baseUrl, string keyword, int page)
    {
        HtmlDocument doc = new HtmlDocument();

        try
        {
            string url = baseUrl + "&K=" + keyword + "&p=" + page;

            //Some steam urls redirect to https for no reason, as the data is also available on http.
            //Could be an error from steam, or an typo from me. Test it out later. For now, crudely replacing will have to do.
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url.Replace("https:", "http:"));
            request.UserAgent = "Steam-Stats Web Crawler";
            request.Timeout = 20000;

            using (WebResponse response = request.GetResponse())
            {
                doc.Load(response.GetResponseStream());
            }
        }
        catch (Exception ex)
        {
            log.WriteEntry("Timeout Error\nURL: " + baseUrl + "&K=" + keyword + "&p=" + page, EventLogEntryType.Error);
        }

        if (doc.DocumentNode.HasChildNodes)
        {
            //if the search returns any results otherwise just skip trying scanning
            if (doc.DocumentNode.SelectSingleNode("//div[@id='resultsMsg']") == null)
            {
                    Parallel.ForEach(doc.DocumentNode.SelectNodes("//a[@class='linkTitle']"), link =>
                                {
                                    string href = link.Attributes["href"].Value;

                                    //get profiles with custom name enabled
                                    if (href.StartsWith("http://steamcommunity.com/id/"))
                                    {
                                        string steamID = href.Substring(29);

                                        DAL db = new DAL("DB");
                                        db.Addparameter("@SteamID", steamID, SqlDbType.NVarChar);
                                        db.ExecuteNonQuery("QueueGathererSteamID", true);
                                    }

                                    //get profiles using the steam64ID
                                    if (href.StartsWith("http://steamcommunity.com/profiles/"))
                                    {
                                        long steam64ID = Convert.ToInt64(href.Substring(35));

                                        DAL db = new DAL("DB");
                                        db.Addparameter("@Steam64ID", steam64ID, SqlDbType.NVarChar);
                                        db.ExecuteNonQuery("QueueGathererSteam64ID", true);
                                    }
                                });

                //crawl next page if available
                HtmlNode pagebtn = doc.DocumentNode.SelectSingleNode("//a[@class='pagebtn' and .='>']");
                if (pagebtn != null)
                {
                    CrawlSteamIDs(baseUrl, keyword, page + 1);
                }
            }
        }
        else
        {
            log.WriteEntry("Error Loading HTML Page: " + doc.ToString() + "\nURL: " + baseUrl + "&K=" + keyword + "&p=" + page, EventLogEntryType.Error);

            //error loading page, try next page instead
            CrawlSteamIDs(baseUrl, keyword, page + 1);
        }
    }
}

来自 eventviwer 的堆栈。源被列为 .NET Runtime

应用程序:SSIDGatherer.exe 框架版本:v4.0.30319 说明:进程因未处理的异常而终止。 异常信息:System.AggregateException 堆: 在 System.Threading.Tasks.Parallel.ForWorker[[System._Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](Int32, Int32, System.Threading.Tasks.ParallelOptions, System.Action1&lt;Int32&gt;, System.Action2, System.Func4&lt;Int32,System.Threading.Tasks.ParallelLoopState,System.__Canon,System.__Canon&gt;, System.Func1, System.Action1<System.__Canon>) at System.Threading.Tasks.Parallel.ForEachWorker[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.__Canon[], System.Threading.Tasks.ParallelOptions, System.Action1, System.Action2&lt;System.__Canon,System.Threading.Tasks.ParallelLoopState&gt;, System.Action3, System.Func4&lt;System.__Canon,System.Threading.Tasks.ParallelLoopState,System.__Canon,System.__Canon&gt;, System.Func5, System.Func1&lt;System.__Canon&gt;, System.Action1) 在 System.Threading.Tasks.Parallel.ForEachWorker[[System._Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System._Canon, mscorlib, Version= 4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.Collections.Generic.IEnumerable1&lt;System.__Canon&gt;, System.Threading.Tasks.ParallelOptions, System.Action1, System.Action2&lt;System.__Canon,System.Threading.Tasks.ParallelLoopState&gt;, System.Action3, System.Func4&lt;System.__Canon,System.Threading.Tasks.ParallelLoopState,System.__Canon,System.__Canon&gt;, System.Func5, System.Func1&lt;System.__Canon&gt;, System.Action1) 在 System.Threading.Tasks.Parallel.ForEach[[System._Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.Collections.Generic.IEnumerable1&lt;System.__Canon&gt;, System.Action1) 在 SSIDGatherer.SSIDGatherer.Treading() 在 System.Threading.ThreadHelper.ThreadStart_Context(System.Object) 在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,System.Threading.ContextCallback,System.Object,布尔) 在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,System.Threading.ContextCallback,System.Object) 在 System.Threading.ThreadHelper.ThreadStart()

【问题讨论】:

  • 能否发布异常的全文,包括堆栈跟踪及其内部异常?
  • 如果没有一个更简短的示例来显示问题或异常详细信息,如果不自己调试代码,任何人几乎不可能告诉您出了什么问题
  • 与其贴出有效的代码,不如贴出一小段无效的代码。
  • 如果我知道是什么部分导致了错误,我可以自己处理。问题是我对出了什么问题一无所知。我尝试在每个 Parallel.ForEach cathing Exeption 和 aggregateExeption 上使用 try catch,但它们从未命中 try catch。我用事件视图中的错误更新了帖子。

标签: c# .net windows service parallel.foreach


【解决方案1】:

尝试在服务的 OnStart 中添加 Debugger.Launch,这样您就可以逐步检查代码并找出问题所在。

【讨论】:

  • 谢谢谢谢,这让调试变得如此简单。原来问题是这样的:源“SSIDGatherer”未在日志“SteamStats”中注册。 (注册在日志'Application'中。) " Source和Log属性必须匹配,或者你可以将Log设置为空字符串,它会自动匹配到Source属性。如何避免这个错误?它似乎经常发生。可能是因为我安装/卸载很多?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-21
  • 2013-01-10
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
  • 1970-01-01
相关资源
最近更新 更多