Pull to refresh
1
0
Վիտալի Լագունով @vitaliy2

Пользователь

Send message

Arctic Connect заморожен, вместо него Far North Fiber.

Теоретически иногда бывает примерно такая ситуация:

  1. Ты сделал хорошую программу.

  2. Выложил на GitHub.

  3. Прошёл год, а эту страницу на GitHub'е никто даже не посетил, кроме тебя.

Наверное, автор попал в подобную ситуацию.

На Youtube, если это неигровое видео, то битрейт на современных кодеках составляет 1 Мбит/с на FullHD. Сервер с шифрованием 10 ГБ/с позволяет обслужить 80 тыс таких пользователей одновременно, что, наверное, эквивалентно минимум 400 тыс активных пользователей сервиса, т.к. люди не смотрят Youtube весь день.

Пусть будет, что процессор служит минимум 4 года, тогда $400 на 400 тыс пользователей - это до 0.002 цента на человека в месяц (до $0.00002/мес). Один показ рекламы принесёт несравнимо больше.

Если это игровое видео, битрейт может быть до 5 Мбит/с, т.е. придётся тратить до $0.0001 на человека/мес, но и это достаточно мало.

На стриминговых сервисах с сериалами, если это качественный сервис, битрейт может достигать 20 Мбит/с, т.е. придётся тратить $0.0004/мес на человека, но при подписке $10/мес эта сумма тоже достаточно мала.

Для сравнения, Netflix на своих серверах вынужден добиваться пиковой производительности до 800 Гб/c

На Netflix достаточно низкие битрейты, вроде что-то около 2 Мбит/с (т.к. Netflix стримит в 720p по-умолчанию). Получается, по их требованиям 1 сервер должен обслуживать 3 миллиона одновременных пользователей, что может соответствовать активной аудитории до 15 миллионов человек. Согласно Википедии, у Netflix 277 млн пользователей, т.е. получается на весь Netflix должно быть 20 стримящих серверов. Я думаю, их всё-таки сильно больше.

Можно зайти с другой стороны. 277 млн пользователей → 50 млн одновременных пользователей → 15000 ГБ/с → 1500 дешёвых процессоров по 10 ГБ/с → $600 тыс → $150 тыс/год.

В 2020 году Netflix потратил $12 млрд на создание контента. $150 тыс на этом фоне не ощущается большой суммой. +Подписка на Netflix не бесплатная.

Вы очень странно пересчитали это в пользователей

В хэндшейках имелись ввиду разовые пользователи. Понятное дело, что у сервиса не может быть 50 млрд пользователей — на Земле просто не живёт столько людей.

Всего мировой трафик измеряется десятками эксабайт в день и немалую его часть составляет HTTP

Общий размер трафика неважен, важно какой % в стоимость вносит шифрование. И этот процент крайне мал. Я полагаю, что стоимость самого трафика где-то в 10 тыс раз превышает стоимость шифрования, а иногда эта разница может доходить и до 100 тыс раз. Стоит ли тогда оно того? Думаю, да.

Да и в целом для шифрования 40 ЭБ/день нужно 100 тыс процессоров по 10 ГБ/с, пусть будет $1 млн/мес. Не такая уж большая сумма для человечества.

Мобильные устройства, где вопрос энергоэффективности

Мне кажется:

  1. Импакт очень маленький. К примеру, если батарея прослужит на 0.001 сек меньше, вряд ли пользователь это заметит. Надо посчитать импакт.

  2. Какое-нибудь разжатие трафика съест несравнимо больше.

Если такие вещи критичны, я бы лучше тогда может бы пошёл со стороны отключения загрузки картинок. Они мало того, что потребляют трафик, но и требуют "разжатия", что прямо супер-дорогая операция по сравнению с шифрованием. Это действительно поможет продлить жизнь батареи может быть даже на несколько секунд или ещё больше (я на самом деле не знаю сколько).

Протокол HTTP/2 показал себя с не лучшей стороны

Может быть. Я когда читал о протоколах мне показалось странным, что QUIC был уже два года на момент выхода HTTP/2, но его не взяли, а потом всё-таки передумали и взяли, но уже в HTTP/3. Если протокол QUIC был плохой, значит его не нужно было брать вообще. Если хороший, то брать сразу. В итоге имеем два протокола вместо одного. При этом, как я понимаю, QUIC на самом деле действительно значительно лучше SPDY, т.е. нужно было брать QUIC.

ChatGPT говорит (возможно, ошибочно), что современные процы могут шифровать 10 ГБ/с и делать 10 тыс хэндшейков в секунду на эллиптических кривых. Т.е. на обычном процессоре за несколько сотен долларов мы можем обслужить до 25 миллиардов пользователей в месяц и отдать до 25 ПБ (петабайт) трафика. В статье явно преувеличена сложность шифрования и требуемые ресурсы.

С момента написания оригинала правда прошло 10 лет — за это время стоимость шифрования упала, но и 10 лет назад это было дёшево. Если у сайта больше миллиарда посещений за месяц, наверное, он найдёт несколько сотен долларов на дополнительный процессор. Если это видеохостинг, трафик тоже наверняка будет намного дороже, предполагаю, что какие-нибудь 600 ПБ трафика обойдутся не менее $200 000, на этом фоне несколько сотен долларов на процессор не такая большая сумма.

Я имел ввиду, что мы вначале в 8 потоков найдём maxValue, например, с помощью функции calculate_part1(array), а потом в 8 потоков найдём aggregatedValue с помощью функции calculate_part2(array, maxValue).

Вот пример на javascript:

//Returns maxValue
function calculate_part1(a) {
	if (!Array.isArray(a) && !ArrayBuffer.isView(a)) throw new TypeError('a must be an Array or a TypedArray');
	if (a.length < 1)                                throw new Error('a.length must be >= 1');
	
	let maxValue = a[0];
	
	for (let i = 1; i < a.length; i++)
		maxValue = Math.max(maxValue, a[i]);
	
	return maxValue;
}

//Returns aggregatedValue
function calculate_part2(a, maxValue, start = 0, end = a.length) {
	const k = (1 / maxValue) ** 3 / 5;
	let sum = -0;
	
	for (let i = start; i < end; i++)
		sum += (maxValue - sum) * a[i] ** 3 * k;
	
	return sum;
}

//Combines few aggregatedValues calculated independently
function calculate_part3(maxValue, ...sums) {
	let ans = -0;
	
	for (const sum of sums) {
		const progress = sum / maxValue;
		ans += progress - ans * progress;  //Need to test if works with negative numbers
	}
	
	return ans * maxValue;
}

//Tests functions above
function test() {
	const EL_COUNT    = 1000,
	      buffer      = typeof SharedArrayBuffer === 'function' ? new SharedArrayBuffer(EL_COUNT * 8) : new ArrayBuffer(EL_COUNT * 8),
	      array       = (new Float64Array(buffer)).map(v => Math.random() * 100),
		  biggerValue = array[(EL_COUNT * 0.8) | 0] = 1000,
	      maxValue    = calculate_part1(array),  //Single-thread version but multi-thread can be used instead
		  
	      //Slow way
		  ans_slow    = calculate_part2(array, maxValue),  //Single-thread version
		  
		  //Fast way
		  sum1        = calculate_part2(array, maxValue, 0,   200),  //Please calc it in thread 1
		  sum2        = calculate_part2(array, maxValue, 200, 400),  //Please calc it in thread 2
		  sum3        = calculate_part2(array, maxValue, 400, 600),  //Please calc it in thread 3
		  sum4        = calculate_part2(array, maxValue, 600, 800),  //Please calc it in thread 4
		  sum5        = calculate_part2(array, maxValue, 800, 1000), //Please calc it in thread 5
		  ans_fast    = calculate_part3(maxValue, sum1, sum2, sum3, sum4, sum5);
	
	console.log(ans_slow);  //237.84063581747668
	console.log(ans_fast);  //237.84063581747665
	console.log(areDoublesEqual_simple(ans_fast, ans_slow));  //true
}

function areDoublesEqual_simple(a, b) {
	return Math.abs(a - b) < 0.00000000000001 || Math.abs(a / b - 1) < 0.00000000000001;
}

test();

Порядок операций здесь неважен, как для подсчёта максимума, так и для подсчёта aggregatedValue (внутри второго цикла), поэтому проще будет поюзать векторные инструкции, которые ускорят значительно сильнее, чем попытка убрать один из циклов.

Также, поскольку порядок операций неважен, можно дополнительно разбить этот массив, к примеру, на 8 частей и считать каждую часть на отдельном ядре, а потом сложить то, что получилось, по формуле. Например, если первая часть массива приблизилась к maxValue на 50% и вторая часть на 90%, то суммарно обе части вместе приблизились к maxValue на 95%.

Такие оптимизации будут и значительно проще для продумывания и реализации, и будут ускорять в разы или даже на порядки больше, чем попытка избавиться от одного из циклов. Хотя если действительно можно избавиться от одного из циклов, с учётом того, что там delta равна (maxValue - aggregatedValue), а не (maxValue - value), то я бы хотел посмотреть, как это возможно.

Если данные идут потоково, и нет возможности сохранить их в память из-за нехватки памяти, могу предложить только считать не от общего maxValue, а от текущего, а если вдруг встретили больше, то немного скорректировать текущее aggregatedValue + пересчитать данные для X последних элементов или запланировать этот пересчёт на потом. Точность при этом упадёт, но примерный ответ будет.

Теперь правда хоть какая-то инфа по оптимизации для этой задачи в Интернете есть, и тестировать LLM теперь на этой задаче сложнее.

Проблема бесконечности в том что они невероятно скучны - в них есть буквально всё что можно придумать.

Не совсем так. Предположим, что вероятность какого-то события или наличия какого-то объекта/штуки ε (эпсилон) или для упрощения 0% при выборке 1 раз. Если сделать выборку бесконечное раз, какова будет вероятность этой штуки? Ответ: неопределённость.

В некоторых случаях эту неопределённость можно очень легко раскрыть, например, с помощью "крутости" бесконечности, которая идёт из теории множеств (континуум и пр.). Если одна бесконечность "круче" другой, то мы можем сразу сказать, что вероятность будет или 0%, или 100%. В других же случаях раскрыть эту неопределённость может быть тяжело или даже невозможно.

Главная фишка тут в том, что бесконечность не ведёт автоматически к вероятностям 100% чего бы то ни было, т.к. итоговая вероятность может компенсироваться другими бесконечностями.

Я когда читал, не заметил точку в конце второго числа, поэтому удивился, что два одинаковых BigInt при сравнении дают false. В реальности же в конце второго числа стоит точка, из-за чего оно хранится как float. Получается сравнение 9007199254740993 == 9007199254740992.0, что логично даёт false.

В каком-то смысле Вы правы, т.к. демократически страны самые развитые и больше всех вносят вклад в глобальное потепление. Но если переформулировать Вашу логику, то это звучит примерно как "Давайте сейчас убьём половину населения Земли, чтобы остановить глобальное потепление и спасти человечество". Наверное, проблему стоит решать по-другому?

А как не зная грамматики переводить? Тут ни думать, ни переводить не получится.

По поводу слов - выше я сказал, что если не знаешь слово, то да, придётся переводить, здесь я не отрицаю. В этом случае ты можешь вспомнить нужное слово на родном или на другом знакомом языке, а потом уже перевести на нужный язык. Хотя это скорее будет перевод конкретного незнакомого слова. Ну или будет полностью смена языка (типа начал думать на одном языке, закончил на другом). Но не полный перевод, когда все мысли формируются на одном языке, а потом переводятся на другой. Такого лично у меня не было.

Впрочем даже без знания грамматики ты всё-равно можешь помнить какие-то выражения/обрывки или мочь составлять очень короткие предложения. Есть языки, которые я плохо знаю, но всё-равно, то, что я могу сказать, я говорю сразу, без внутреннего перевода. Но я просто не могу сказать что угодно на таких языках. При этом я могу даже не знать русских аналогов сказанного (или их просто не существует).

Вы, когда программируете, переводите в уме со своего старого языка программирования на новый или пишете сразу на новом? Мне кажется, что процент тех, кто переводит, не так высок, хотя исследование я не проводил.

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

Выше я имел ввиду, что я никогда не переводил с родного языка ни на каком уровне.

Если не знаешь какие-то слова, то да, переводишь. А так нет. Иногда я практиковался в переводе с изучаемого языка, но не на изучаемый.

Даже если это не китаец, то всё-равно:

  1. Все увидели пример России, и теперь знают, насколько это опасно.

  2. В Китае постоянно говорят, что нужно воевать с Тайванем. Это факт. Т.е. китайцы готовы убивать даже других китайцев.

  3. В Китае диктатура. Это факт. Диктатуры рано или поздно приведут к концу света (если это не произойдёт раньше по другом причинам).

Ведь вы будете думать на своём языке а потом переводить

Это ведь неправда. И на японском, и на английском языках я всегда сразу думаю на конечном языке (даже раньше, когда хуже их знал). Не думаю, что кто-то реально вначале составляет предложение на другом языке, а потом переводит.

Причём в моём случае, кстати, свои мысли с японского на русский я не смогу перевести (это слишком сложно). Придётся очень долго думать над каждой фразой.

У Вас тоже ошибка:

Только, не смотря

Только, несмотря

В исходной статье был символ "??‍♂️", а не "?‍♂️", поэтому такие различия.

В исходной статье, кстати, был применён символ "??‍♂️" (5 кодовых точек Unicode), а в переводе стал символ "?‍♂️" (4 кодовых точки Unicode). Из-за этого, если запустить примеры, то получится не тот результат, который написан в этих же примерах, т. к. в примерах указан символ ?‍♂️, а длина строки посчитана для символа из исходной статьи.

Автор недооценивает возможности современного Javascript:

function calcGraphemeCount(s, lang = 'en') {
	const segmenter = new Intl.Segmenter(lang, {granularity: 'grapheme'});
	return [...segmenter.segment(s)].length;
}

console.log(calcGraphemeCount('?‍♂️'));  //Выдаёт 1

Оптимизированная версия:

class MyString() {
	static segmenter_en_grapheme = new Intl.Segmenter('en', {granularity: 'grapheme'});
	
	static calcGraphemeCount(s) {
		let count = 0;
		
		for (const segment of MyString.segmenter_en_grapheme.segment(s))
			count++;
		
		return count;
	}
}

console.log(MyString.calcGraphemeCount('?‍♂️'));  //Выдаёт 1

Что здесь происходит:

  1. Создаём экземпляр класса Intl.Segmenter, который служит для разбиения текста на графемы, слова или предложения. В данном случае выбираем графемы.

  2. Применяем этот класс к строке, чтобы посчитать количество графем.

Если нужно, можно получить графему и её позицию по индексу в строке:

const segmenter_en_grapheme = new Intl.Segmenter('en', {granularity: 'grapheme'}),
      segmentObjs   = segmenter_en_grapheme.segment('abc?‍♂️def'),
      segmentObjAt5 = segmentObjs.containing(5);  //{segment: '?‍♂️', index: 3}

const grapheme    = segmentObjAt5.segment,                 //?‍♂️
      index_start = segmentObjAt5.index,                   //3
      index_end   = segmentObjAt5.index + grapheme.length; //8

Класс Intl.Segmenter можно использовать и для других целей, например, чтобы разбить японский или китайский текст, в котором нет пробелов, на слова. Правда сейчас пока в японском разбивает ну очень плохо, например, слово 間違う успешно считается за одно слово, но если поменять форму, например, на 間違えてる, то считается аж целых 5 слов (間+違+え+てる) вместо одного слова (間違えてる) или хотя бы двух слов (間違えて+る).

Впрочем, соглашусь, что, возможно, было бы интересно увидеть в JS свойство вида String.prototype.graphemeCount, чтобы можно было написать как-то так:

'?‍♂️'.graphemeCount;  //1

Для integer, наверное, одинаковые, для double необязательно (из-за потерь в точности):

double i = 9007199254740991;
i = i + 2 + 2;  //9007199254740994
i = i + 4;      //9007199254740996

Не так много людей посылают другу другу .com файлы, к тому же сейчас Винда обычно использует расширение .cmd вместо предыдущего .com.

При скачивании может быть любое расширение на усмотрение автора сайта, необязательно zip.

1
23 ...

Information

Rating
Does not participate
Location
Yerevan, Yerevan, Армения
Registered
Activity

Specialization

Fullstack Developer, Web Developer
Lead
JavaScript
Node.js
HTML
CSS
Web development