Skip to content

Instantly share code, notes, and snippets.

@vergeev
Last active March 23, 2017 14:42
Show Gist options
  • Save vergeev/eba5ab7bf1704253cc01aa78bcb07005 to your computer and use it in GitHub Desktop.
Save vergeev/eba5ab7bf1704253cc01aa78bcb07005 to your computer and use it in GitHub Desktop.
Comparison of friends.get and friends.getOnline VK API methods

Что измеряем

Необходимо выяснить, какой из методов (friends.get или friends.getOnline) тратит больше времени на получение имени и фамилии очередного друга пользователя, находящегося в сети. Причем необходимо отсеивать тех, кто в сети не находится.

Как измеряем

Для тестов были выбраны три пользователя: id1 (724 друга на время теста), id5070786 (4611 друзей) и id177168718 (9922 друга). Каждое измерение запускало оба метода по 20 раз. Для каждого пользователя проводилось по три измерения. Способ, использующий friends.get был обозначен цифрой 2, friends.getOnline -- 1.

Результаты измерений

id1

№1

$ python3 measurements.py 1 -n 20
mean: 
1: 0.003892 2: 0.002767 delta: 0.001124
max: 
1: 0.006189 2: 0.004677 delta: 0.001512
min: 
1: 0.002597 2: 0.001613 delta: 0.000984

№2

$ python3 measurements.py 1 -n 20
mean: 
1: 0.003439 2: 0.002455 delta: 0.000984
max: 
1: 0.005072 2: 0.004250 delta: 0.000822
min: 
1: 0.002160 2: 0.001540 delta: 0.000620

№3

python3 measurements.py 1 -n 20
mean: 
1: 0.004076 2: 0.003412 delta: 0.000664
max: 
1: 0.006750 2: 0.005130 delta: 0.001620
min: 
1: 0.002309 2: 0.001683 delta: 0.000627

id5070786

№4

$ python3 measurements.py 5070786 -n 20
mean:
1: 0.005103 2: 0.004412 delta: 0.000691
max:
1: 0.009284 2: 0.006967 delta: 0.002317
min: 
1: 0.003269 2: 0.002512 delta: 0.000757

№5

$ python3 measurements.py 5070786 -n 20
mean: 
1: 0.008317 2: 0.004883 delta: 0.003434
max: 
1: 0.057713 2: 0.007388 delta: 0.050326
min: 
1: 0.003186 2: 0.002171 delta: 0.001015

№6

python3 measurements.py 5070786 -n 20
mean: 
1: 0.004735 2: 0.004877 delta: -0.000142
max: 
1: 0.007543 2: 0.015527 delta: -0.007984
min: 
1: 0.002979 2: 0.002376 delta: 0.000603

id177168718

№7

$ python3 measurements.py 177168718 -n 20
mean: 
1: 0.002503 2: 0.001999 delta: 0.000504
max: 
1: 0.003425 2: 0.002650 delta: 0.000775
min: 
1: 0.001392 2: 0.001441 delta: -0.000048

№8

$ python3 measurements.py 177168718 -n 20
mean: 
1: 0.002301 2: 0.002202 delta: 0.000099
max: 
1: 0.004480 2: 0.003547 delta: 0.000933
min: 
1: 0.001670 2: 0.001511 delta: 0.000159

№9

$ python3 measurements.py 177168718 -n 20
mean: 
1: 0.002463 2: 0.002297 delta: 0.000166
max: 
1: 0.003240 2: 0.006651 delta: -0.003411
min: 
1: 0.001735 2: 0.001558 delta: 0.000178

Выводы

  • В среднем, способ с friends.getOnline работал дольше.
  • Разрыв редко превышал 0.001 секунды на онлайн-друга.
  • Более большие разрывы, скорее всего, провоцировал сам ВКонтакте. Например, в измерении №5 и №9 наблюдается большой разрыв в максимальном времени исполнения, причем как в одну, так и другую сторону.
  • С увеличением количества друзей у человека разрыв по времени между двумя способами уменьшался. Это связано с тем, что способ с friends.getOnline работает тем эффективнее, чем меньше отношение количества онлайн-друзей к общему числу друзей.
  • Способ с friends.getOnline мало оправдывает себя, потому что упомянутое отношение у людей обычно недостаточно маленькое (этому способствует и ограничение на колчество друзей).
  • Способ с friends.getOnline имеет race condition: если в перерыве между загрузкой списка друзей и скачиванием списка онлайн-друзей человек добавляет онлайн-друга, возникает KeyError.
  • Способ с friends.getOnline позволяет получить информацию о том, с какого устройства человек зашел на сайт.
  • Способ с friends.getOnline является примером преждевременной оптимизации: он не улучшает времени исполнения (хотя, чисто в теории, мог бы) и добавляет функциональность, не требовавшуюся в задании.

Как воспроизвести

  1. Зарегистрировать standalone-приложение ВКонтакте, https://vk.com/editapp?act=create, вставить APP_ID в эту ссылку и перейти по ней: https://oauth.vk.com/authorize?client_id=<APP_ID>&display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=friends,offline&response_type=token&v=5.52. Авторизовать приложение, а затем скопировать все между access_token= и & и положить в переменную окружения TEST_VK_ACCESS_TOKEN.
  2. Скачать vk.py и measurements.py в одну папку. Запустить measurements.py так, как показано выше (см. "Результаты измерений").
import argparse
import os
import time
from timeit import default_timer as timer
from vk import fetch_online_friends1
from vk import fetch_online_friends2
def get_time_per_online_friend1(user_id):
# friends.getOnline
start_time = timer()
friends = fetch_online_friends1(access_token, args.user_id)
elapsed_time = timer() - start_time
return elapsed_time / len(friends)
def get_time_per_online_friend2(user_id):
# friends.get
start_time = timer()
friends = fetch_online_friends2(access_token, args.user_id)
elapsed_time = timer() - start_time
return elapsed_time / len(friends)
def parse_cli_arguments():
parser = argparse.ArgumentParser()
parser.add_argument('user_id', type=int)
parser.add_argument('-n', '--number_of_experiments',
type=int, default=10)
return parser.parse_args()
if __name__ == '__main__':
args = parse_cli_arguments()
access_token = os.environ['TEST_VK_ACCESS_TOKEN']
times1 = []
for _ in range(args.number_of_experiments):
times1.append(get_time_per_online_friend1(args.user_id))
time.sleep(1)
times2 = []
for _ in range(args.number_of_experiments):
times2.append(get_time_per_online_friend2(args.user_id))
time.sleep(1)
mean1 = sum(times1) / len(times1)
mean2 = sum(times2) / len(times2)
meandelta = mean1 - mean2
print('mean: ')
print('1: %f 2: %f delta: %f' % (mean1, mean2, meandelta))
max1 = max(times1)
max2 = max(times2)
maxdelta = max1 - max2
print('max: ')
print('1: %f 2: %f delta: %f' % (max1, max2, maxdelta))
min1 = min(times1)
min2 = min(times2)
mindelta = min1 - min2
print('min: ')
print('1: %f 2: %f delta: %f' % (min1, min2, mindelta))
import os
import time
import requests
def make_vk_api_request(method, **params):
method_url = 'https://api.vk.com/method/%s' % method
params['v'] = '5.62'
response = requests.get(method_url, params=params)
response.raise_for_status()
return response.json()
def fetch_friend_names(access_token, count, user_id=None, offset=0):
''' For thorough description of the request parameters, refer to
friends.get documentation: https://vk.com/dev/friends.get
'''
params = {'user_id': user_id,
'access_token': access_token,
'fields': 'online', # this way we can get the names of the friends
'count': count,
'offset': offset,
}
return make_vk_api_request('friends.get', **params)['response']['items']
def fetch_friend_list(access_token, user_id=None):
max_friends = 5000 # VK won't return more because of 'fields' parameter
friends = fetch_friend_names(access_token, max_friends, user_id)
if len(friends) == max_friends:
friends += fetch_friend_names(access_token, max_friends, user_id,
offset=max_friends)
return friends
def fetch_online_friend_ids(access_token, user_id=None, online_mobile=1):
''' For thorough description of the request parameters, refer to
friends.getOnline documentation: https://vk.com/dev/friends.getOnline
'''
params = {'user_id': user_id,
'online_mobile': 1, # separate mobile online from desktop online
'access_token': access_token,
}
online_friend_ids = make_vk_api_request('friends.getOnline', **params)
return online_friend_ids['response']
def turn_friend_list_into_dictionary(friend_list):
friends = {}
for friend in friend_list:
friends[friend['id']] = friend
return friends
def fetch_online_friends1(access_token, user_id=None):
friend_list = fetch_friend_list(access_token, user_id)
friends = turn_friend_list_into_dictionary(friend_list)
online_friend_ids = fetch_online_friend_ids(access_token, user_id)
online_desktop_ids = online_friend_ids['online']
online_mobile_ids = online_friend_ids['online_mobile']
online_friends = []
for online_id in online_desktop_ids + online_mobile_ids:
friend = friends[online_id]
friend_name = ' '.join((friend['first_name'], friend['last_name']))
online_friends.append({'name': friend_name,
'url': 'https://vk.com/id%d' % online_id})
return online_friends
def fetch_online_friends2(access_token, user_id=None):
friend_list = fetch_friend_list(access_token, user_id)
online_friends = []
for friend in friend_list:
if not friend['online']:
continue
friend_name = ' '.join((friend['first_name'], friend['last_name']))
friend_id = friend['id']
online_friends.append({'name': friend_name,
'url': 'https://vk.com/id%d' % friend_id})
return online_friends
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment