在c#中为应用程序添加多线程场景

时间:2013-12-05 10:23:39

标签: c# multithreading

我在c#中开发了一个应用程序。课程结构如下。

Form1 => UI表单。有背景工作者,处理工具栏和“确定”按钮。

SourceReader,TimedWebClient,HttpWorker,ReportWriter // clases做了一些工作

Controller =>有全部控制权。从“确定”按钮单击创建此类名为“cntrl”的实例。此cntrlr是Form1.cs中的全局变量。         (在Controler的构造函数中,我创建了SourceReader,TimedWebClient,HttpWorker,ReportWriter实例。)

然后我调用后台worker的RunWorkerAsync()。 其中代码如下。

   private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        int iterator = 1;

        for (iterator = 1; iterator <= this.urlList.Count; iterator++)
        {
            cntrlr.Vmain(iterator-1);
            backgroundWorker1.ReportProgress(iterator);             
        }
    }

在报告时,ReportProgress会更新进度条 上面提到的urlList有1000个url。 cntlr.Vamin(int i)处理整个过程。我想将任务交给几个线程,每个线程必须处理100个网址。虽然不禁止访问其他实例或方法,但对ReportWriter的访问应限制为一次只有一个线程。我找不到办法做到这一点。如果有人有想法或答案,请解释。

3 个答案:

答案 0 :(得分:1)

如果你想同时使用相同的方法限制多个线程,那么我会使用Semaphore类来促进所需的线程限制;这是怎么......

信号量就像一个卑鄙的夜总会保镖,它一直提供俱乐部容量,不允许超过这个限制。一旦俱乐部满员,没有其他人可以进入...队列在外面建立起来。然后当一个人离开时,另一个人可以进入(类比感谢J. Albahari)。

值为1的Semaphore等同于MutexLock,但Semaphore没有所有者,因此它是线程无知的。任何主题都可以在Release上调用Semaphore,而使用Mutex / Lock只有获得Mutex / Lock的主题可以释放它

现在,对于您的情况,我们可以使用Semaphore来限制并发性并防止太多线程一次执行特定代码。在下面的示例中,五个线程尝试进入夜总会,只允许进入三个......

class BadAssClub
{
    static SemaphoreSlim sem = new SemaphoreSlim(3);
    static void Main()
    {
        for (int i = 1; i <= 5; i++) 
            new Thread(Enter).Start(i);
    }

    // Enfore only three threads running this method at once.
    static void Enter(int i)
    {
        try
        {
            Console.WriteLine(i + " wants to enter.");
            sem.Wait();
            Console.WriteLine(i + " is in!");
            Thread.Sleep(1000 * (int)i);
            Console.WriteLine(i + " is leaving...");
        }
        finally
        {
            sem.Release();
        }
    }
}

请注意,SemaphoreSlimSemaphore类的轻量级版本,并且会产生大约四分之一的开销。它足以满足您的需求。

我希望这会有所帮助。

答案 1 :(得分:1)

我想我会使用ThreadPool而不是后台工作者,并且给每个线程1,而不是100个url来处理。线程池将限制它一次启动的线程数,因此您不必担心一次获得1000个请求。看看这里有一个很好的例子

http://msdn.microsoft.com/en-us/library/3dasc8as.aspx

答案 2 :(得分:0)

感觉更有冒险精神?考虑使用TPL DataFlow下载一堆网址:

var urls = new[]{
    "http://www.google.com",
    "http://www.microsoft.com",
    "http://www.apple.com",
    "http://www.stackoverflow.com"};
var tb = new TransformBlock<string, string>(async url => {
    using(var wc = new WebClient())
    {
        var data = await wc.DownloadStringTaskAsync(url);
        Console.WriteLine("Downloaded : {0}", url);
        return data;
    }
}, new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 4});
var ab = new ActionBlock<string>(data => {
    //process your data
    Console.WriteLine("data length = {0}", data.Length);
}, new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 1});
tb.LinkTo(ab); //join output of producer to consumer block
foreach(var u in urls)
{
    tb.Post(u);
}
tb.Complete();

请注意如何显式控制每个块的并行性,这样您就可以并行收集但不进行并发处理(例如)。

用nuget抓住它。容易。