出于测试目的,我有2000个图像URI(字符串)的数组,我使用此功能异步下载。经过一些谷歌搜索和测试并尝试,我想出了两个都可以工作的 2个函数(坦白地说, downloadFilesAsync2 会抛出一个 InvalidArgumentException 在最后一行)。
函数 downloadFilesAsync2 基于类 GuzzleHttp \ Promise \ EachPromise ,而 downloadFilesAsync1 基于 GuzzleHttp \ Pool < / strong>课程。
这两个函数都能很好地异步下载2000个文件,同时最多可以下载10个线程。
我知道它们可以工作,但是没有别的。我想知道是否有人可以解释这两种方法,一种方法是否优于另一种方法,含义等等。
from PIL import Image
import urllib.request
import skimage
def f(row):
URL=row['ThumbnailURL']
#URL = 'http://www.moma.org/media/W1siZiIsIjU5NDA1Il0sWyJwIiwiY29udmVydCIsIi1yZXNpemUgMzAweDMwMFx1MDAzZSJdXQ.jpg?sha=137b8455b1ec6167'
with urllib.request.urlopen(URL) as url:
with open('temp.jpg', 'wb') as f:
f.write(url.read())
tutu = Image.open('temp.jpg')
val=skimage.exposure.is_low_contrast(tutu, fraction_threshold=0.4, lower_percentile=1, upper_percentile=99, method='linear')
return val
data3['lowcontornot'] = data3.apply(f, axis=1)
答案 0 :(得分:1)
首先,我将解决downloadFilesAsync2
方法中的 InvalidArgumentException 。这种方法实际上存在两个问题。两者都与此有关:
$requests[] = $client->request('GET', $uri, ['sink' => $loc]);
第一个问题是Client::request()
是包装$client->requestAsync()->wait()
的同步实用程序方法。 $client->request()
将返回Psr\Http\Message\ResponseInterface
的一个实例,结果$requests[]
实际上将被ResponseInterface
的实现所填充。这就是最终导致 InvalidArgumentException 的原因,因为$requests
不包含任何Psr\Http\Message\RequestInterface
,并且从Pool::__construct()
内部引发了异常。
此方法的更正版本应包含类似于以下内容的代码:
$requests = [
new Request('GET', 'www.google.com', [], null, 1.1),
new Request('GET', 'www.ebay.com', [], null, 1.1),
new Request('GET', 'www.cnn.com', [], null, 1.1),
new Request('GET', 'www.red.com', [], null, 1.1),
];
$pool = new Pool($client, $requests, [
'concurrency' => 10,
'fulfilled' => function(ResponseInterface $response) {
// do something
},
'rejected' => function($reason, $index) {
// do something error handling
},
'options' => ['sink' => $some_location,],
]);
$promise = $pool->promise();
$promise->wait();
要回答第二个问题“这两种方法之间有什么区别”,答案很简单,没有答案。为了解释这一点,让我复制并粘贴Pool::__construct()
:
/**
* @param ClientInterface $client Client used to send the requests.
* @param array|\Iterator $requests Requests or functions that return
* requests to send concurrently.
* @param array $config Associative array of options
* - concurrency: (int) Maximum number of requests to send concurrently
* - options: Array of request options to apply to each request.
* - fulfilled: (callable) Function to invoke when a request completes.
* - rejected: (callable) Function to invoke when a request is rejected.
*/
public function __construct(
ClientInterface $client,
$requests,
array $config = []
) {
// Backwards compatibility.
if (isset($config['pool_size'])) {
$config['concurrency'] = $config['pool_size'];
} elseif (!isset($config['concurrency'])) {
$config['concurrency'] = 25;
}
if (isset($config['options'])) {
$opts = $config['options'];
unset($config['options']);
} else {
$opts = [];
}
$iterable = \GuzzleHttp\Promise\iter_for($requests);
$requests = function () use ($iterable, $client, $opts) {
foreach ($iterable as $key => $rfn) {
if ($rfn instanceof RequestInterface) {
yield $key => $client->sendAsync($rfn, $opts);
} elseif (is_callable($rfn)) {
yield $key => $rfn($opts);
} else {
throw new \InvalidArgumentException('Each value yielded by '
. 'the iterator must be a Psr7\Http\Message\RequestInterface '
. 'or a callable that returns a promise that fulfills '
. 'with a Psr7\Message\Http\ResponseInterface object.');
}
}
};
$this->each = new EachPromise($requests(), $config);
}
现在,我们是否将其与downloadFilesAsync1
方法中的简化代码进行比较:
$promises = (function () use ($client, $uris) {
foreach ($uris as $uri) {
yield $client->requestAsync('GET', $uri, ['sink' => $some_location]);
}
})();
(new \GuzzleHttp\Promise\EachPromise(
$promises, [
'concurrency' => 10,
'fulfilled' => function (\Psr\Http\Message\ResponseInterface $response) {
// do something
},
'rejected' => function ($reason, $index) {
// do something
},
])
)->promise()->wait();
在两个示例中,都有一个生成承诺的生成器,该承诺可以解析为ResponseInterface
的实例,并且该生成器连同配置数组(已完成可调用,已拒绝可调用,并发)也被馈送到{ {1}}。
总结:
EachPromise
在功能上与使用downloadFilesAsync1
相同,只是没有Pool
内置的错误检查。
Pool::__construct()
中存在一些错误,这些错误会导致在实例化downloadFilesAsync2
时,在接收到 InvalidArgumentException 之前,以同步方式下载文件。
我唯一的建议是:使用对您而言更直观的方式。