создание кеша для более быстрого доступа к списку диктов в python - PullRequest
0 голосов
/ 24 апреля 2019

Я пишу программу на 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-адрес оттуда и сохранить его.Я попробовал несколько способов, создавая массивы.Даже если это займет некоторое время.Как сделать это возможным .....

Ответы [ 2 ]

1 голос
/ 24 апреля 2019

Вы упомянули, что у вас могут быть миллионы веб-сайтов, поэтому одним из способов решения этой проблемы будет использование фреймворков, специализирующихся на кэшировании.Одним из таких примеров может быть Redis.

Установка и начало работы с Redis

Ниже приведен пример кода для SET и получения данных.

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, попробуйте

cachetools Пример cachetools

1 голос
/ 24 апреля 2019

В общем случае кеш должен быть структурой данных, которая быстрее массива.Массив будет в худшем случае всегда принимать столько итераций, сколько у него есть записей (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']
...