Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading Perl并行HTTP请求-内存不足_Multithreading_Perl - Fatal编程技术网

Multithreading Perl并行HTTP请求-内存不足

Multithreading Perl并行HTTP请求-内存不足,multithreading,perl,Multithreading,Perl,首先,我是Perl新手。 我想在Perl中的RESTAPI上发出多个(例如160个)HTTP GET请求。一个接一个地执行它们需要很多时间,所以我考虑并行运行这些请求。因此,我使用线程同时执行更多请求,并将并行请求的数量限制为10个。 这在我第一次运行程序时效果很好,第二次在第40次请求后运行“内存不足” 代码如下:(@url包含请求的160个url) while(@url){ 我的@threads; 对于(my$j=0;$jget($url)}; } 对于我的$thread(@threads)

首先,我是Perl新手。 我想在Perl中的RESTAPI上发出多个(例如160个)HTTP GET请求。一个接一个地执行它们需要很多时间,所以我考虑并行运行这些请求。因此,我使用线程同时执行更多请求,并将并行请求的数量限制为10个。 这在我第一次运行程序时效果很好,第二次在第40次请求后运行“内存不足”

代码如下:(@url包含请求的160个url)

while(@url){
我的@threads;
对于(my$j=0;$j<10和@URL;$j++){
my$url=shift(@url);
推送@threads,异步{$ua->get($url)};
}
对于我的$thread(@threads){
我的$response=$thread->join;
打印“$response\n”;
}
}
所以我的问题是,为什么我第一次没有用完内存,而是第二次(我的代码中缺少了一些关键的东西)?我能做些什么来防止它?
或者有更好的方法执行并行GET请求吗?

我不知道为什么在第一次运行时没有OOM错误,而在第二次运行时会出现OOM错误;当您运行Perl脚本并退出Perl二进制文件时,它会将其所有内存释放回操作系统。处决之间没有任何保留。REST服务每次返回的数据是否完全相同?也许在你第二次跑步时会有更多的数据,这会把你推到边缘

我注意到的一个问题是,您正在启动10个线程并将它们运行到完成,然后再生成10个线程。更好的解决方案可能是工作线程模型。在程序开始时生成10个线程(或任意多个),将URL放入队列,并允许线程自己处理队列。下面是一个可能有帮助的快速示例:

use strict;
use warnings;
use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

my @thr = map {
    threads->create(sub {
        my @responses = ();
        while (defined (my $url = $q->dequeue())) {
            push @responses, $ua->get($url);
        }
        return @responses;
    });
} 1..10;

$q->enqueue($_) for @urls;
$q->enqueue(undef) for 1..10;

foreach (@thr) {
    my @responses_of_this_thread = $_->join();
    print for @responses_of_this_thread;
}

注意,我还没有测试它以确保它工作。在本例中,您将创建一个新的线程队列并生成10个工作线程。每个线程都将阻塞dequeue方法,直到有东西要读取。接下来,将所有URL排队,并为每个线程设置一个
unde
。当没有更多的工作要执行时,
undef
将允许线程退出。此时,线程将完成并处理工作,最后您将通过join收集响应。

每当我需要异步解决方案Perl时,我都会首先查看框架。在这个特殊的例子中,我使用了它,它将允许我们同时发送多个请求,并提供一个回调机制,您可以在其中处理http响应

Perl线程非常可怕,可能会使应用程序崩溃,尤其是当您加入或分离它们时。如果响应不需要很长时间来处理,那么单线程POE解决方案将非常有效

但有时,我们不得不依赖线程,因为应用程序由于长时间运行的任务而被阻塞。在这些情况下,在启动应用程序中的任何内容之前,我会创建一定数量的线程。然后使用Thread::Queue,我将数据从主线程传递给这些工作线程,并且从不加入/分离它们;为了稳定起见,请始终保持它们在附近。 (并非对所有情况都是理想的解决方案。)


POE现在支持线程,每个线程都可以运行POE::内核。内核可以通过TCP套接字相互通信(POE提供了良好的解锁接口)

为了回答您的问题,REST服务每次都返回完全相同的数据。我尝试了你的代码,我不得不更改一行:
my@thr=map{threads->create(sub{my$url=$q->dequeue();return除非定义$url;$ua->get($url)}1..10这只执行10个请求,还是我又犯了错误?然而,有时它会完成所有10个请求,有时我会收到OOM错误。@user1771548 Joel在这么快编写代码时犯了一个小错误。我更新了代码,现在它在线程中循环,应该解决这部分问题。不过,对于内存问题没有任何想法。@user1771548您对
$ua
使用的是什么模块?快速搜索LWP和线程安全会发现一些提到潜在问题的线程。你有没有考虑过使用LWP::Parallel(如果你还没有的话)?@user1771548还有,你使用的是什么版本的Perl(
Perl-v
),你在什么平台上运行它?@Joel我在使用LWP::UserAgent,还没有考虑过LWP::Parallel。版本是5.16.1,平台是Windows7,32位。用这样一个简单的问题来解决所有POE的东西可能会有些过头。此外,还有学习所有额外API的问题。一旦你理解了这些问题,Perl线程就相当优雅了。现在,IMO是一个更好的框架,更易于使用。
use strict;
use warnings;
use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

my @thr = map {
    threads->create(sub {
        my @responses = ();
        while (defined (my $url = $q->dequeue())) {
            push @responses, $ua->get($url);
        }
        return @responses;
    });
} 1..10;

$q->enqueue($_) for @urls;
$q->enqueue(undef) for 1..10;

foreach (@thr) {
    my @responses_of_this_thread = $_->join();
    print for @responses_of_this_thread;
}