首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程写入问题

线程写入问题
EN

Stack Overflow用户
提问于 2010-09-10 21:38:28
回答 4查看 148关注 0票数 0

我有一个问题。我准备了很多关于最好的阅读的页面,像这样的http://www.albahari.com/threading/part4.aspx

一切都写得很好,但我还是有线程方面的问题。我同时运行6个线程。我正在解析一些数据,这些数据必须存储到数据库中。但是我不能将相同的数据存储两次。

现在我在数据库中得到了许多复制的数据。我怎样才能防止这种情况。我认为lock()并不好用。我想使用Monitor,但我不知道这是否可以。

这是线程代码:

代码语言:javascript
复制
CultureInfo contentCulture = (CultureInfo)propertyBag["LanguageCulture"].Value;
                string cultureDisplayValue = "N/A";
                if (!contentCulture.IsNull())
                {
                    cultureDisplayValue = contentCulture.DisplayName;
                }

                AllocConsole();

                Console.Out.WriteLine();
                Console.Out.WriteLine("Url: {0}", propertyBag.Step.Uri);
                Console.Out.WriteLine("Content type: {0}", propertyBag.ContentType);
                Console.Out.WriteLine("Content length: {0}", propertyBag.Text.IsNull() ? 0 : propertyBag.Text.Length);
                Console.Out.WriteLine("Depth: {0}", propertyBag.Step.Depth);
                Console.Out.WriteLine("Culture: {0}", cultureDisplayValue);
                Console.Out.WriteLine("ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
                Console.Out.WriteLine("Thread Count: {0}", crawler.ThreadsInUse);
                Console.Out.WriteLine();

                ConsoleCount++;

                if (ConsoleCount > 1000)
                {
                    Console.Clear();
                    ConsoleCount = 0;
                }

                HtmlDocument htmlDoc = new HtmlDocument();
                Encoding documentEncoding = htmlDoc.DetectEncoding(propertyBag.GetResponse());
                propertyBag.GetResponse().Seek(0, SeekOrigin.Begin);

                if (documentEncoding != null)
                {
                    htmlDoc.Load(propertyBag.GetResponse(), documentEncoding, true);
                }
                else
                {
                    htmlDoc.Load(propertyBag.GetResponse(), true);
                }

                string htmlContent = htmlDoc.DocumentNode.OuterHtml;
                if (string.IsNullOrEmpty(htmlContent)) return;

                IAdvertismentsDao advertismentsDao = DaoFactory.GetAdvertisementsDao();
                List<TagValuePair> listTagValuePair = HtmlHelper.GetTagsAndValues(htmlContent);
                string link = propertyBag.Step.Uri.ToString();

                if (string.IsNullOrEmpty(link))
                {
                    link = propertyBag.ResponseUri.ToString();
                }


                Advertisements ad =
                    new CrawlerManager(DaoFactory, ConnectionString).GetAdvertismentFromHtmlContent(
                        listTagValuePair, Agency, link);

                if (ad != null)
                {
                    if (!advertismentsDao.AdvertisementUrlExist(ad.Url))
                    {
                        if (
                            !advertismentsDao.AdvertisementExist(ad.Price, ad.HollidayDuration, ad.Name,
                                                                 ad.Description, ad.City, ad.Area, ad.Country,
                                                                 ad.Agency))
                        {
                            advertismentsDao.Save(ad);
                            advertismentsDao.CommitChanges();
                        }
                    }
                    else
                    {
                        if (advertismentsDao.ChekIfNeedUpdate(ad))
                        {
                            Advertisements advertisements = advertismentsDao.GetByUrl(ad.Url);

                            advertisements.Price = ad.Price;
                            advertisements.HollidayDuration = ad.HollidayDuration;
                            advertisements.Name = ad.Name;
                            advertisements.Description = ad.Description;
                            advertisements.DepartureDate = ad.DepartureDate;

                            advertismentsDao.SaveOrUpdate(advertisements);
                            advertismentsDao.CommitChanges();
                        }
                    }

                    InvokeEvent(ad, string.Empty);
                }
                else
                    InvokeEvent(null, link);
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-09-10 22:09:05

我猜你对以下内容有意见:

代码语言:javascript
复制
if (!advertismentsDao.AdvertisementUrlExist(ad.Url))
{
    if (
        !advertismentsDao.AdvertisementExist(ad.Price, ad.HollidayDuration, ad.Name,
                                             ad.Description, ad.City, ad.Area, ad.Country,
                                             ad.Agency))
    {
       advertismentsDao.Save(ad);
       advertismentsDao.CommitChanges();
    }
}

线程#1完全有可能看到Url和广告不存在--然后被线程#2抢先。线程#2也会看到Url和广告不存在,然后两个线程都会尝试保存。

关于如何解决这个问题,有几点想法:

  1. 拆分你的输入,这样没有两个线程在同一个Advertisment
  2. Move上工作“如果存在”逻辑到数据库中,并利用行锁和围绕整个“如果存在,然后保存”部分的
  3. 锁。
  4. 使用一个基于ad.GetHashCode()的互斥锁来确保一次只有一个线程在处理类似的广告。您可以从AdvertisementUrlExist调用中检索这个互斥锁-并在那里阻塞,直到它可用。当然,您基本上是在if exists检查的point.
  5. Remove上实现行级锁定,只需将数据写入数据库。您可以使用SELECT.

每晚或按需进行聚合

票数 1
EN

Stack Overflow用户

发布于 2010-09-10 21:50:06

问题是您没有正确地拆分正在解析的数据。你说你有六个线程在解析数据,但是很明显,其中一些线程正在解析相同的数据。

看看你的代码,我认为问题出在你的propertyBag上。我不确定这是什么,但我认为它没有给每个线程提供正确的数据来解析。您可能想看看ConcurrentQueue类,以获得一些想法。

票数 1
EN

Stack Overflow用户

发布于 2010-09-10 21:47:53

你必须在你的数据上定义一个唯一的索引,它是“业务关键字”,也就是说,在你的例子中,一些take使得行是“唯一的”。

如果您两次插入相同的数据,数据库将抛出异常。然后,您可以忽略此异常(已有数据)或更新现有行(例如,计算项目出现的次数)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3685011

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档