我正在尝试重构我的项目,现在我正在尝试寻找最佳方法以提高应用程序的性能。
问题1.自旋锁与互锁
要创建一个计数器,该方法具有更好的性能。
Interlocked.increament(ref counter)
或
SpinLock _spinlock = new SpinLock()
bool lockTaken = false;
try
{
_spinlock.Enter(ref lockTaken);
counter = counter + 1;
}
finally
{
if (lockTaken) _spinlock.Exit(false);
}
如果我们需要给另一个计数器(例如counter2
)加油,是否应该声明另一个SpinLock
对象?还是足以使用另一个boolean
对象?
问题2。处理嵌套任务或更好的替换
在此应用程序的当前版本中,我使用任务,将每个新任务添加到数组中,然后使用Task.WaitAll()
经过大量研究,我发现使用Parallel.ForEach
具有更好的性能,但是如何控制当前线程的数量呢?我知道我可以在MaxDegreeOfParallelism
参数中指定ParallelOptions
,但是问题出在这里,每次运行crawl(url)
方法时,它只会创建另一个有限数量的线程,这意味着如果我设置了{ {1}}到10,每次运行MaxDegree
时,都会创建另一个+10,对吗?那么如何防止这种情况发生?我应该使用信号量和线程代替Paralel吗?还是有更好的方法?
crawl(url)
问题3.所有作业(和嵌套作业)完成时通知。
我的最后一个问题是,我所有工作完成后如何理解?
致谢。
答案 0 :(得分:1)
这里有很多误解,请指出几个。
要创建一个计数器,哪种方法具有更好的性能。
两者都取决于您的确切情况
经过大量研究,我只是使用Parallel.ForEach进行了研究 性能更好
这也是非常可疑的,实际上是错误的。再次取决于您要做什么。
我知道我可以在ParallelOptions中指定MaxDegreeOfParallelism 参数,但是问题出在这里,每次执行crawl(url)方法时,它只会创建另一个有限数量的线程
再一次,这是错误的,这是您自己的实现细节,并取决于您如何执行。而且 TPL MaxDegreeOfParallelism
只是一个建议,它只会做它认为对您最有利的尝试。
我应该使用信号量和线程代替Paralel吗?或有一个 更好的方法?
答案是肯定的。
好,让我们看看您在做什么。你说你正在做一个履带。每次您访问Internet或网络资源或文件系统时,爬虫都会访问Internet,(简而言之)您正在等待IO完成端口回调。这就是所谓的 IO工作负载。
使用 IO Bound 任务,我们不想将线程池与等待 IO完成端口的线程捆绑在一起。它效率低下,您正在消耗宝贵的资源,以等待有效暂停的线程上的回调。
因此,对于 IO绑定工作,我们不想启动新任务,也不想使用 Parallel ForEach 等待使用完线程等待事件发生。用于 IO绑定任务的最合适的现代模式是async
和await
模式。
对于CPU限制的工作(如果要使用尽可能多的CPU),请粉碎线程池,请使用 TPL Parallel 或许多有效的任务。
async
和await
模式在完成端口上可以很好地工作,因为与其闲置地等待回调,不如将其退回并允许它们被重用。是的
...
但是我建议使用的是另一种方法,您可以利用async
和await
并控制并行度。这使您可以更好地使用线程池,而不会用尽资源等待回调,并允许IO成为IO。我给你TPL DataFlow
ActionBlock
和TransformManyBlocks
这个主题比一个简单的工作示例略高一点,但是我可以向您保证,它是您正在做的事情的合适路径。我建议您看看以下链接。
总而言之,有很多方法可以做您想做的事,并且有很多技术。但是最主要的是,您对并行编程有一些非常复杂的想法。您需要阅读书籍,浏览博客,并开始从头开始获得一些真正扎实的设计原则,并停止尝试通过收集少量信息来为自己解决所有问题。
祝你好运
答案 1 :(得分:0)
我建议为此考虑一下Microsoft的Reactive Framework。您可以这样编写Crawl
函数:
public IObservable<Response> Crawl(string url)
{
return
from r in Observable.Start(() => GetResponse(url))
from l in r.Links.ToObservable()
from r2 in Crawl(l).StartWith(r)
select r2;
}
然后称呼它试试
IObservable<Response> crawls = Crawl("www.microsoft.com");
IDisposable subscription =
crawls
.Subscribe(
r => { /* process each response as it arrives */ },
() => { /* All crawls complete */ });
完成。它为您处理所有线程。只是NuGet“ System.Reactive”。