我在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的访问应限制为一次只有一个线程。我找不到办法做到这一点。如果有人有想法或答案,请解释。
答案 0 :(得分:1)
如果你想同时使用相同的方法限制多个线程,那么我会使用Semaphore
类来促进所需的线程限制;这是怎么......
信号量就像一个卑鄙的夜总会保镖,它一直提供俱乐部容量,不允许超过这个限制。一旦俱乐部满员,没有其他人可以进入...队列在外面建立起来。然后当一个人离开时,另一个人可以进入(类比感谢J. Albahari)。
值为1的Semaphore
等同于Mutex
或Lock
,但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();
}
}
}
请注意,SemaphoreSlim
是Semaphore
类的轻量级版本,并且会产生大约四分之一的开销。它足以满足您的需求。
我希望这会有所帮助。
答案 1 :(得分:1)
我想我会使用ThreadPool而不是后台工作者,并且给每个线程1,而不是100个url来处理。线程池将限制它一次启动的线程数,因此您不必担心一次获得1000个请求。看看这里有一个很好的例子
答案 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抓住它。容易。