【问题标题】:creating cache for faster access of list of dicts in python创建缓存以更快地访问python中的字典列表
【发布时间】:2019-09-13 10:07:51
【问题描述】:

我正在编写一个 python 程序,用于使用套接字模块获取网站的 IP 地址。 在这里,我有一个包含 n 个网站和数字的字典列表。

以下是一些示例数据:

data_list = [{'website': 'www.google.com', 'n': 'n1'}, {'website': 'www.yahoo.com', 'n': 'n2'}, {'website': 'www.bing.com', 'n': 'n3'}, {'website': 'www.stackoverflow.com', 'n': 'n4'}, {'website': 'www.smackcoders.com', 'n': 'n5'}, {'website': 'www.zoho.com', 'n': 'n6'}, {'website': 'www.quora.com', 'n': 'n7'}, {'website': 'www.elastic.co', 'n': 'n8'}, {'website': 'www.google.com', 'n': 'n9'}, {'website': 'www.yahoo.com', 'n': 'n10'}, {'website': 'www.bing.com', 'n': 'n11'}, {'website': 'www.stackoverflow.com', 'n': 'n12'}, {'website': 'www.smackcoders.com', 'n': 'n13'}, {'website': 'www.zoho.com', 'n': 'n14'}, {'website': 'www.quora.com', 'n': 'n15'}, {'website': 'www.elastic.co', 'n': 'n16'}, {'website': 'www.google.com', 'n': 'n17'}, {'website': 'www.yahoo.com', 'n': 'n18'}, {'website': 'www.bing.com', 'n': 'n19'}, {'website': 'www.stackoverflow.com', 'n': 'n20'}]

这是我的程序:

import socket
import time


data_list = [{'website': 'www.google.com', 'n': 'n1'}, {'website': 'www.yahoo.com', 'n': 'n2'}, {'website': 'www.bing.com', 'n': 'n3'}, {'website': 'www.stackoverflow.com', 'n': 'n4'}, {'website': 'www.smackcoders.com', 'n': 'n5'}, {'website': 'www.zoho.com', 'n': 'n6'}, {'website': 'www.quora.com', 'n': 'n7'}, {'website': 'www.elastic.co', 'n': 'n8'}, {'website': 'www.google.com', 'n': 'n9'}, {'website': 'www.yahoo.com', 'n': 'n10'}, {'website': 'www.bing.com', 'n': 'n11'}, {'website': 'www.stackoverflow.com', 'n': 'n12'}, {'website': 'www.smackcoders.com', 'n': 'n13'}, {'website': 'www.zoho.com', 'n': 'n14'}, {'website': 'www.quora.com', 'n': 'n15'}, {'website': 'www.elastic.co', 'n': 'n16'}, {'website': 'www.google.com', 'n': 'n17'}, {'website': 'www.yahoo.com', 'n': 'n18'}, {'website': 'www.bing.com', 'n': 'n19'}, {'website': 'www.stackoverflow.com', 'n': 'n20'}]

field = "website"
action = "append"
max_retry = 1
hit_cache_size = 10
cache = []
d1 = []

for data in data_list:
    temp={}
    for item in data:
        if item ==field:
            if data[item]!="Not available":
                try:
                    ad=socket.gethostbyname(data[item])
                    if len(cache)<hit_cache_size:
                        cache.append({data[item]:ad})
                    else:
                        cache=[]
                    if action=="replace":
                        temp[item]=ad
                    elif action=="append":
                        temp[item]=str([data[item],ad])
                except:
                    count=0
                    while(True):
                        try:
                            ad=socket.gethostbyname(data[item])
                        except:
                            count+=1
                            if count==max_retry:
                                if action=="replace":
                                    temp[item]="Unknown"
                                elif action=="append":
                                    temp[item]=str([data[item],"Unknown"])
                                break
                            else:
                                continue    
            else:
                temp[item]="Not available"
        else:
            temp[item]=data[item]
    temp['timestamp']=time.ctime()   
    d1.append(temp)
print(d1)

在这里,d 可以拥有数百万个网站。因此,我的代码需要更多时间。所以我创建了一个缓存来存储一些websites 和他们的ip。缓存大小在hit_cache_size 中定义。如果列表中出现相同的网站地址,则应先检查缓存,而不是使用套接字模块进行检查。如果网站地址在那里,它应该从那里获取 ip 并保存。我通过创建数组尝试了一些方法。尽管这需要一些时间。如何让它成为可能......

【问题讨论】:

  • 我会开始使用不同的变量名而不是ij 等等,这真的很难阅读。使用富有表现力的变量名称,那么这里的人将有机会更快地回答,如果您将代码传递给其他程序员也是如此。
  • 更改了代码中的变量,使其更易于阅读......
  • 为什么将缓存大小限制为 10 个元素,为什么要在达到 10 个元素时重置缓存?
  • 这只是一个示例代码。实际上,缓存大小将是 5000 或更多。这是临时缓存。达到一定限制后会被重置。我只想检查缓存而不是套接字模块以快速处理它。但我不知道实现它的方法。

标签: python python-3.x sockets caching ip-address


【解决方案1】:

您提到您可能拥有数百万个网站,因此解决此问题的一种方法是使用专门用于缓存的框架。 Redis 就是这样的例子之一。

Installing and getting started with redis

以下只是设置和获取数据的示例代码。

import redis

# step 2: define our connection information for Redis
# Replaces with your configuration information
redis_host = "localhost"
redis_port = 6379
redis_password = ""


def hello_redis():
    """Example Hello Redis Program"""

    # step 3: create the Redis Connection object
    try:

        # The decode_repsonses flag here directs the client to convert the responses from Redis into Python strings
        # using the default encoding utf-8.  This is client specific.
        r = redis.StrictRedis(host=redis_host, port=redis_port, password=redis_password, decode_responses=True)

        # step 4: Set the hello message in Redis 
        r.set("msg:hello", "Hello Redis!!!")

        # step 5: Retrieve the hello message from Redis
        msg = r.get("msg:hello")
        print(msg)        

    except Exception as e:
        print(e)


if __name__ == '__main__':
    hello_redis()

现在使用上面的示例,您可以在代码库中实现它。下面是我编写的一个示例,您可以在其中进行简单更改的插件。

def operate_on_cache(operation, **value):
    """Operate on Redis Cache"""
    try:

        # The decode_repsonses flag here directs the client to convert the responses from Redis into Python strings
        # using the default encoding utf-8.  This is client specific.
        r = redis.StrictRedis(host=redis_host, port=redis_port, password=redis_password, decode_responses=True)

        # Set the key value pair
        if operation == 'set':
            msg = r.set("{}:ip".format(value['site_name']), value['ip'])

        #Retrieve the key
        elif operation == 'get':
            msg = r.get('{}:ip'.format(value['site_name']))
        # If not get/set then throw exception.
        return msg
    except Exception as e:
        print(e)


# Snippet of your code where of how you could implement it.


if data[item] != "Not available":
    try:
        if operate_on_cache('get', site_name = data[item]):
            ad = socket.gethostbyname(data[item])
            operate_on_cache('set', site_name=data[item], ip=ad)

这只是如何使用 Redis 进行缓存的基础知识。如果您正在寻找 python 的纯 python 实现,请尝试

缓存工具 Example of cachetools

【讨论】:

    【解决方案2】:

    一般来说,缓存应该是一种比数组更快的数据结构。在最坏的情况下,数组的迭代次数总是与它的条目一样多(n)看看https://wiki.python.org/moin/TimeComplexity

    例如:如果您在此处查找 'c' 的映射,则需要 3 次迭代。

    entries = [('a', 1), ('b', 2), ('c', 3)]
    result = None
    for key, val in entries:
       if key == 'c':
          result = val
    print(result)
    

    如果您想加快对缓存的访问速度,请使用 python dict。这将为您提供更快的访问速度。通常这会给你一个运行时n log n 的平均情况,这要好得多。很好的副作用:也更好阅读。

    entries = {'a': 1, 'b': 2, 'c': 3}
    result = entries['c']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多