【发布时间】:2015-09-30 12:27:24
【问题描述】:
经过长时间的工作,我无法通过multi-threading 使用这种方法获得任何成功。非常感谢您的帮助。
我有一个listview,其中第一列包含我们稍后在其他方法中需要的网址。秒列是结果。
我正在创建两个带有 url 的 ArrayLists 并将它们(带有 arraylist 的 url)发送到该方法,然后在该方法中,使用 httpwebrequest,我从每个 url 获取页面标题。
所以问题是当我尝试触发 5 threads 时,它的工作方式如下:
(U:url,R:结果)
u1 = r1 (所以,我必须得到 u1 的结果为 r1..)
但我越来越喜欢:
u1 = r1, u2 = r1, u3(or4) = r1, u4 = r1, u5=r2(or3,4)
但我期待的是: u1=r1, u2=r2, u3=r3, u4=r4...
为了更好的解释,请查看下面的图片
然后我尝试将Lock 关键字与私有对象一起使用,但随后我丢失了multi-threading。它的工作原理与我一样,但一一例外。不要同时触发 5 个不同的线程并等待完成线程 1 以移动到下一个线程。
///主类///
/* A store of all created threads. */
ArrayList _threads = new ArrayList();
/* A store of all FileDownloader objects. */
ArrayList _instances = new ArrayList();
private int _activeDownloadCount = 0;
object _lockObject = new object();
按钮:
_instances = new ArrayList();
_threads = new ArrayList();
_activeDownloadCount = 0;
FileDownloader download = null;
foreach (ListViewItem item in listviewUrl.Items)
{
item.SubItems[9].Text = "Not started";
download = new FileDownloader(item.SubItems[0].Text);
item.Tag = download;
try
{
ThreadStart tsDelegate = new ThreadStart(download.Download);
download.DownloadStarting += new FileDownloader._delDownloadStarting(download_DownloadStarting);
download.DownloadCompleted += new FileDownloader._delDownloadCompleted(download_DownloadCompleted);
Thread t = new Thread(tsDelegate);
t.Name = item.SubItems[0].Text;
_threads.Add(t);
_instances.Add(download);
}
catch
{
item.SubItems[9].Text = "Error";
}
}
StartDownload();
开始下载方法:
int j = 0;
int limit = int.Parse(numThreadSearch.Text);
int iCount = 0;
lock (_lockObject)
{
iCount = _instances.Count;
}
if (iCount != 0)
{
foreach (Thread thread in _threads)
{
FileDownloader file = ((FileDownloader)_instances[j]);
if (file._IsStarted == false)
{
lock (_lockObject)
{
thread.Start();
Console.WriteLine(_activeDownloadCount);
_activeDownloadCount++;
}
}
if (_activeDownloadCount == limit)
{
break;
}
j++;
}
}
else
{
/* If all the files have downloaded, we will do something here.
}
方法完成时:
void download_DownloadCompleted(FileDownloader thread, bool isSuccess)
{
lock (_lockObject)
{
_activeDownloadCount--;
}
PageRankReturns(FileDownloader._PageRankReturn, thread);
RemoveFromInternalPool(thread);
StartDownload();
}
delegate void delSetStatus(string Status, FileDownloader f);
private void PageRankReturns(string Status, FileDownloader f)
{
if (listviewUrl.InvokeRequired)
{
delSetStatus s = new delSetStatus(PageRankReturns);
this.Invoke(s, new object[] { Status, f });
}
else
{
foreach (ListViewItem item in listviewUrl.Items)
{
if (item.Tag == f)
{
/* Use locking to synchronise across mutilple thread calls. */
lock (_lockObject)
{
item.SubItems[2].Text = Status;
}
break;
}
}
}
}
private void RemoveFromInternalPool(FileDownloader thread)
{
int i = 0;
foreach (FileDownloader f in _instances)
{
if (f == thread)
{
/* If the file has downloaded, remove it from our pool. */
lock (_lockObject)
{
_threads.Remove(_threads[i]);
_instances.Remove(f);
break;
}
}
i++;
}
}
/// 二等舱 ///
#region Fields
private string _DocumentUrl = string.Empty;
private string _DirectoryPath = string.Empty;
public bool _IsDownloading = false;
public bool _IsDownloadSuccessful = false;
public bool _IsStarted = false;
#endregion
#region Delegates
public delegate void _delDownloadStarting(FileDownloader thread);
public delegate void _delDownloadCompleted(FileDownloader thread, bool isSuccess);
public delegate void _delDownloadCWorking(FileDownloader thread);
#endregion
#region Events
public event _delDownloadStarting DownloadStarting;
public event _delDownloadCompleted DownloadCompleted;
protected static readonly object locker = new object();
public static string pageTitleResult= string.Empty;
public static string _pageTitleResult
{
get { return pageTitleResult; }
}
public FileDownloader(string documentUrl)
{
_DocumentUrl = documentUrl;
}
//下载方法 //
public void Download()
{
_IsStarted = true;
DownloadStarting(this);
_IsDownloading = true;
_IsDownloadSuccessful = false;
// with lock keyword it works one by one//
//without lock or monitor.enter keyword then it works as i tried explain above u1 = r1, u2 = r1, ur3 = r1, u4=r3 etc...
try
{
string pageHtml = getHtml(_DocumentUrl);
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
//html agibility works with returned string from gethtml...
// string pageTitle = html agibility work result, it's string...
pageTitleResult = pageTitle
_IsDownloadSuccessful = true;
_IsDownloading = false;
/* raise a download completed event. */
DownloadCompleted(this, _IsDownloadSuccessful);
}
catch
{
_IsDownloadSuccessful = false;
}
Thread.Sleep(10);
}
锁定对象:
protected static readonly object locker = new object();
好吧,我只是在excel中做了一个例子来展示它是如何工作的......
【问题讨论】:
-
"pageTitleResult = pageTitle;" - 什么是“pageTitleResult”、“pageTitle”?它们的定义在哪里以及在哪里使用?
-
@AlexanderKiselev 我刚刚编辑了这部分。它只是 html 敏捷包的工作,不管有没有它,线程问题都不会改变,这就是为什么我删除了这部分以稍微清除代码。
-
我在你的代码中找不到,你在 ListView 列中插入字符串:item.Subitems[1],url 在哪里,item.Subitems[2],结果在哪里,如果我能正确理解你的帖子。
-
@AlexanderKiselev 感谢您抽出宝贵时间,我刚刚添加了用于多线程的其他必要方法。
-
在方法 PageRankReturns() 中,尝试“if (f.Equals(item.Tag))”而不是“if (item.Tag == f)”。
标签: c# multithreading listview arraylist