0

我希望我的表单应用程序启动多个线程以从站点并行下载源代码。

这只是主应用程序的一部分。

图片链接:http
://www.abload.de/img/pic9aym7.png 我不允许发布图片。

    private void buttonstart_Click(object sender, EventArgs e)
    {
         //check the list below
    }

    private void buttonabort_Click(object sender, EventArgs e)
    {
         //should always could abort the process/threads. (close all webcontrols ect)
    }
  1. 它应该开始读取框中的数字。
  2. 对于每个数字,它应该打开一个网络浏览器或 httpwebrequest 以下载一些源代码并计算运行次数(在本例中为 4 次运行)。
    因此,如果网站类似于“http://www.bla.com/”,则应将运行添加到变量的末尾(http://www.bla.com/1-4)。
  3. 将源解析为不同的字符串。(strWebsiteString1、strWebsiteString2 等等。我稍后会用到它们)

  4. 如果这样做了,它应该读取一些表(从字符串)并将它们解析为数组。(此处相同,array1[3]、array2[3],供将来使用)
    为了获取表格,我想我将使用 htmlagilitypack。我已经为控制台编写了这个 htmlagilitything。我只需要为我的表单应用程序重建它,并更改控制台写入行以将其放入一些数组中。

    但我对其他/更好的解决方案持开放态度。

  5. 我解析到数组中的所有数据现在应该显示在 datagridcolumns 中。每次运行都会得到自己的行。但是,当我尝试将项目添加到组合框列中时,我在每个组合框列中都会遇到错误。
  6. 为了以正确的顺序获取它们并知道它来自哪个浏览器数据,column1 将获取运行次数。

我自己已经试过了。我被线程分别卡住了。而且datagridview也很麻烦。

帮我一个忙,帮助我解决这个问题,并向我展示一个片段/示例可以帮助我。

4

1 回答 1

0

这是一个清楚的例子,展示了我在上面的评论中所说的内容。它使用锁而不是互斥锁,但你会明白的。这是一个使用多线程作业生产者的简单代码,所有生产者都将信息添加到相同的(锁定的)资源中,并且一个消费者每秒运行一次以与表单控件(在这种情况下为 ListBox)交互并清除作业缓存。

您可以在此处找到更多信息http://www.albahari.com/threading/part2.aspx

public partial class Form1 : Form
{
    static readonly Queue<Job> queue = new Queue<Job>();

    public Form1()
    {
        InitializeComponent();
        //starts the timer to run the ProcessJobs() method every second
        System.Threading.Timer t = new System.Threading.Timer(obj => { ProcessJobs(); }, null, 5000, 1000);                
    }               

    /// <summary>
    /// Called by informations producers to add jobs to the common queue
    /// </summary>        
    private void AddJob(Job job)
    {
        lock (queue)
        {
            queue.Enqueue(job);
        }
    }

    /// <summary>
    /// Common queue processing by the consumer
    /// </summary>
    private void ProcessJobs() {            
        Job[] jobs;
        lock (queue)
        {
            jobs = queue.ToArray();
            queue.Clear();
        }
        foreach(Job job in jobs){       
            this.Invoke(new Action(delegate {
                listBox1.Items.Add(job.Name);
            }));
        }
    }

    /// <summary>
    /// Producer
    /// </summary>        
    private void JobsProducer(string name) {
        for (int i = 0; i < 10; i++)
        {
            Random r = new Random();
            System.Threading.Thread.Sleep(r.Next(1,10)*50);
            this.AddJob(new Job(string.Format("Job({0}) n.{1}", name, i)));
        }
    }

    /// <summary>
    /// Starts the jobs producers
    /// </summary>        
    private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            string producerName = string.Format("Producer{0}", i);
            new System.Threading.Timer(obj => { JobsProducer(producerName); }, null, 0, System.Threading.Timeout.Infinite);
        }
    }       
}

public class Job
{
    //whatever -informations you need to exchange between producer and consumer
    private string name;
    public string Name { get { return name; } }
    public Job(string name) {
        this.name = name;
    }
}  

在这里您可以找到一个使用 Dictionary 来保存多个作业结果的示例:

Dictionary<string, string[]> jobs = new Dictionary<string, string[]>();
//adds an array to the dictionary
//NB: (array it's not well suited if you don't know the values or the size in advance...you should use a List<string>)
jobs.Add("jobNumber1", new string[]{"a","b"});
//gets an array from the dictionary
string[] jobNumber1;
if (!jobs.TryGetValue("jobNumber1", out jobNumber1))
     throw new ApplicationException("Couldn't find the specified job in the dictionary"); 
于 2012-07-28T13:03:09.243 回答