我正在用Scrapy构建Spider / Scraper,并且想知道哪种方法更有效:将API包装器对象初始化一次作为类属性?还是用每个URL请求重新初始化?我想知道整体效率和内存(泄漏)的情况,因为这将是一个相当大的项目(数百万个请求)。
案例1 :
# init API wrapper ONCE as class attribute
class ScrapySpider():
api = SomeAPIWrapper()
urls = [
'https://website.com',
# ... +1mil URLs
]
def request(self):
for url in urls:
yield Request(url)
def parse(self, response):
yield self.api.get_meta(response.url)
案例2 :
# init new API wrapper on EACH request
class ScrapySpider():
urls = [
'https://website.com',
# ... +1mil URLs
]
def request(self):
for url in urls:
yield Request(url)
def parse(self, response):
api = SomeAPIWrapper()
yield api.get_meta(response.url)
答案 0 :(得分:2)
在示例代码中,使用class属性(案例1)应该更有效。
答案 1 :(得分:1)
这个问题没有通用的,一刀切的答案-它取决于对象实例化的代价,在最佳/平均/最坏情况下最终实例化实例的频率,以及在示例中使用类属性(而不是实例属性),是否可以在主机类的所有实例之间共享该对象。
请注意,替代项还有另外两个术语:
1 /在初始化程序中创建的每个实例属性:
class ScrapySpider():
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
self.api = SomeAPIWrapper()
避免了使用class属性可能会带来的并发访问问题,并且
2 /一个缓存的属性
class ScrapySpider():
@property
def api(self):
if not hasattr(self, "_cached_api"):
self._cached_api = ApiWrapper()
return self._cached_api
这还可以防止在需要它之前创建ApiWrapper实例(如果创建它很昂贵并且不总是需要它可能会很有用),但是会增加属性访问的开销。