-2

我正在尝试重构我的项目,现在我正在尝试寻找提高应用程序性能的最佳方法。

问题 1. SpinLock vs Interlocked

要创建计数器,哪种方式性能更好。

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()

经过大量研究,我发现 usingParallel.ForEach具有更好的性能,但是如何控制当前线程的数量?我知道我可以MaxDegreeOfParallelismParallelOptions参数中指定a,但问题出在这里,每次crawl(url)方法运行时,它只会创建另一个有限数量的线程,我的意思是如果我设置MaxDegree为10,每次crawl(url)运行,都会创建另一个+10,是吗?对吧?,那我该如何防止呢?我应该使用信号量和线程而不是并行吗?还是有更好的方法?

public void Start() {
    Parallel.Invoke(() => { crawl(url) } );
}


crawl(string url) {
    var response =  getresponse(url);
    Parallel.foreach(response.links, ParallelOption, link => {
        crawl(link);
    });
}

问题 3. 当所有作业(和嵌套作业)完成时通知。

我的最后一个问题是,我如何才能了解我的所有工作何时完成?

4

2 回答 2

2

这里有很多误解,我只指出一些。

要创建计数器,哪种方式性能更好。

他们都这样做,具体取决于您的具体情况

经过大量研究后,我发现使用 Parallel.ForEach 具有更好的性能

这也很可疑,而且实际上是错误的。再一次,这取决于你想做什么。

我知道我可以在 ParallelOptions 参数中指定 MaxDegreeOfParallelism,但问题就在这里,每次 crawl(url) 方法运行时,它只会创建另一个有限数量的线程

这又是错误的,这是你自己的实现细节,取决于你如何做。TPLMaxDegreeOfParallelism只是一个建议,它只会做它认为启发式地认为最适合你的事情。

我应该使用信号量和线程而不是并行吗?还是有更好的方法?

答案是肯定的。


好的,让我们看看你在做什么。你说你在做一个爬虫。爬虫访问互联网,每次您访问互联网或网络资源或文件系统时,您(简单地说)都在等待 IO 完成端口回调。这就是所谓的IO 工作负载

对于IO Bound任务,我们不想将线程池与等待IO 完成端口的线程捆绑在一起。这是低效的,您正在使用宝贵的资源等待有效暂停的线程上的回调。

所以对于IO 绑定的工作,我们不想启动新任务,也不想使用Parallel ForEach来等待,用尽线程等待事件发生。最适合IO 绑定任务的现代模式是asyncandawait模式。

对于 CPU 密集型工作(如果您想使用尽可能多的 CPU)破坏线程池,请使用TPL Parallel或尽可能多的有效任务。

asyncand模式适用于await完成端口,因为它不会无所事事地等待回调,而是将线程返回并允许它们被重用。

...

但是,我建议使用另一种方法,您可以利用asyncawait控制并行化程度。这让你可以善待你的线程池,不会耗尽等待回调的资源,让 IO 成为 IO。我给你TPL DataFlow ActionBlockTransformManyBlocks


这个主题略高于一个简单的工作示例,但我可以向您保证,它是您正在做的事情的合适路径。我建议您查看以下链接。

总之,有很多方法可以做你想做的事情,并且有很多技术。但主要是你对并行编程有一些非常不正确的想法。您需要阅读书籍,访问博客,并从头开始获得一些真正可靠的设计原则,并且不要试图通过挑选少量信息来为自己解决这一切。

于 2018-08-06T02:38:01.670 回答
-1

我建议为此查看 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”。

于 2018-08-06T12:40:42.997 回答