我有一个问题。我准备了很多关于最好的阅读的页面,像这样的http://www.albahari.com/threading/part4.aspx。
一切都写得很好,但我还是有线程方面的问题。我同时运行6个线程。我正在解析一些数据,这些数据必须存储到数据库中。但是我不能将相同的数据存储两次。
现在我在数据库中得到了许多复制的数据。我怎样才能防止这种情况。我认为lock()并不好用。我想使用Monitor,但我不知道这是否可以。
这是线程代码:
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);发布于 2010-09-10 22:09:05
我猜你对以下内容有意见:
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和广告不存在,然后两个线程都会尝试保存。
关于如何解决这个问题,有几点想法:
ad.GetHashCode()的互斥锁来确保一次只有一个线程在处理类似的广告。您可以从AdvertisementUrlExist调用中检索这个互斥锁-并在那里阻塞,直到它可用。当然,您基本上是在if exists检查的point.SELECT.每晚或按需进行聚合
发布于 2010-09-10 21:50:06
问题是您没有正确地拆分正在解析的数据。你说你有六个线程在解析数据,但是很明显,其中一些线程正在解析相同的数据。
看看你的代码,我认为问题出在你的propertyBag上。我不确定这是什么,但我认为它没有给每个线程提供正确的数据来解析。您可能想看看ConcurrentQueue类,以获得一些想法。
发布于 2010-09-10 21:47:53
你必须在你的数据上定义一个唯一的索引,它是“业务关键字”,也就是说,在你的例子中,一些take使得行是“唯一的”。
如果您两次插入相同的数据,数据库将抛出异常。然后,您可以忽略此异常(已有数据)或更新现有行(例如,计算项目出现的次数)。
https://stackoverflow.com/questions/3685011
复制相似问题