I want to introduce you to my two
most favorite performance techniques,
batching and caching.
As we already talked about,
some functions or
operations have a specific amount of
overhead involved with them that is
different than the performance
costs of the operation itself.
For example, loading data into a new
place in memory before executing on it,
or sorting a set of values before
doing a search through it.
When executed multiple times,
where multiples are really big number,
this overhead can become a serious
performance burden for your application.
Batching is the process of
fixing this performance problem
by trying to eliminate the per execution
overhead of these operations, kind of
like sharing a car instead of everyone
driving themselves, thus saving gas.
This is most often seen in your code
where you have to prepare your data
before actually operating on it.
Now, for example, let's say the most
efficient way to find a value
existing in a set is to sort it, and
then execute a binary search on it.
Now, wait to, to be clear, this isn't
actually the most efficient way,
but just stay with me,
I'm trying to make a point here.
Anyhow, the simplest way to do this
would be to write a function that,
given a set and a value,
would sort the set and then search
it to see if the value exists in it.
Now, this may be fine for
some performance level but
let's say you've got like 10,000
values you want to test, and
the size of the set is in the millions.
Suddenly you're incurring
a ton of overhead per test
in the form of the sort.
The answer here is pretty clear.
You'd want to create a sorted
version of the set once, and
then allow all 10,000 values to be
tested for inclusion after that point.
This is batching in action.
We factored out the operation that
is repeated and do it over once.
Now, similar to this is actually
a concept known as caching and
is by far the most important performance
technique you can understand,
mainly because it drives everything
in modern computer technology.
Take your computer, for example.
The whole point of your RAM hardware is
to provide a place to store information
that's faster to access for
the CPU than the hard drive is.
Or take networking, and
look at the modern internet itself,
huge warehouses of servers called data
centers exist all over the world.
Their only purpose is to store or
cache frequently accessed content so
that your computer doesn't have to hit
a server 12,000 miles away every time
your friend in Egypt posts a picture.
Well, unless of course you're in Egypt,
but, you know, you get the point.
Now in your code, the most common place
that you can find optimizations for
caching has to do with data that
is calculated multiple times, but
the result is always the same.
For example, if you're in the middle
of a loop that you're calculating
the derivative of a four by four matrix,
and
that result is always the same, then
you're actually wasting performance,
recomputing it for
each iteration of that loop.
Instead, compute and save the results of
that derivation outside of the loop, and
then let your inner portions of
the loop reference that cached result.
The reason that I love batching and
caching so much is that pretty much
every performance improvement
that you can think of,
including the ones that we're
talking about in this course,
is effectively a variance of
these two basic techniques.
And if you're serious about
becoming a performance ninja,
then you better become a pro
at what it means to leverage
the awesome power of these techniques.
So, let's get started.
أود أن أعرفك على أفضل تقنيتين
من تقنيات الأداء لدي،
وهما: الإرسال في دفعات،
والتخزين المؤقت.
وكما تحدثنا سابقًا،
فبعض الوظائف أو العمليات
تتضمن وجود قدر محدد من الكلفة معها
والتي تختلف عن تكاليف الأداء
للعملية نفسها.
على سبيل المثال، تحميل البيانات
في مكان جديد في الذاكرة قبل التنفيذ عليها،
أو تصنيف مجموعة من القيم
قبل إجراء بحث خلالها.
عندما يتم تنفيذها عدة مرات،
وعندما يكون عدد المرات كبير جدًا،
فإن هذه الكلفة قد تكون عبء ثقيل
على الأداء بالنسبة لتطبيقك.
الإرسال في دفعات
هو عملية إصلاح لمشاكل الأداء
عن طريق محاولة الحد
من كلفة التنفيذ لتلك العمليات،
مثلما تتشارك في سيارة بدلًا من أن يقود
كل فرد على حدة، وبالتالي توفر الوقود.
وهذا ملاحظ جدًا في الكود
حيث عليك تحضير البيانات
قبل العمل عليها بالفعل.
مثلًا، لنقل إن أكثر الطرق فعالية
للعثورعلى قيمة موجودة ضمن مجموعة
هو بفرزها، ثم تنفيذ بحث ثنائي عليها.
الآن، انتظر حتى تتضح الأمور،
فهذه ليست الطريقة المثلى،
لكن ابقَ معي فحسب،
فأنا أحاول توضيح أمر ما هنا.
على أي حال، أبسط طريقة
لفعل ذلك هي ببرمجة وظيفة
لها مجموعة وقيمة،
لفرز المجموعة ثم البحث فيها
لنرى إن كانت القيمة موجودة فيها.
الآن، قد يبدو هذا جيدًا
لبعض مستويات الأداء
لكن لنقل أنه لديك عشرة آلاف قيمة
تحتاج لاختبارها،
وأن حجم المجموعة بالملايين.
وفجأة تتحمل عناء الكثير
من الكلفة لكل اختبار
على شكل فرز.
والجواب هنا واضح جدًا.
ستحتاج لإنشاء نسخة مفرزة
من المجموعة مرة واحدة
ثم تسمح باختبار عشرة آلاف قيمة
للاندماج بعد هذه النقطة.
هذه هي تقنية الإرسال بالدفعات
أثناء العمل.
لقد أخرجنا العملية المتكررة من حساباتنا
وقمنا بها مرة واحدة فقط.
الآن، وبشكل مشابه يوجد مفهوم آخر
يعرف باسم التخزين المؤقت
وهو يعتبر إلى حد بعيد أهم تقنية
من تقنيات الأداء يمكن أن تفهمها،
وهذا بسبب أنها تحرك بشكل أساسي كل شيء
في تكنولوجيا الحاسوب الحديثة.
فلنأخذ حاسوبك على سبيل المثال.
الفكرة الرئيسية للرامات
هي توفير مساحة لتخزين المعلومات
يمكن الوصول إليها بوحدة المعالجة
بطريقة أسرع من القرص الصلب.
أو خذ مثلًا شبكات الاتصال،
وانظر إلى الإنترنت الحديث نفسه،
حيث يوجد مخازن عملاقة من الخوادم
تسمى مراكز البيانات ومنتشرة حول العالم.
وغرضها الوحيد هو تخزين أو عمل تخزين مؤقت
للمحتوى الذي يتم الوصول إليه تكرارًا
بحيث لا يحتاج حاسوبك إلى الوصول
لخادم يبعد إثني عشرة ألف ميل
في كل مرة يرسل لك فيها صديق من مصر صورة.
حسنًا، إلا إذا كنت في مصر بالطبع،
لكن، لقد فهمتَ بالتأكيد.
الآن في الكود، المكان الشائع الذي يمكنك
أن تجد فيه تحسينات للتخزين المؤقت
يتعلق بالبيانات التي يتم حسابها عدة مرات،
ولكن تكون نتيجتها دائمًا متشابهة.
على سبيل المثال، عندما تكون
في منتصف حلقة تكرارية تحسب بها
مستخرج مصفوفة 4×4،
وتكون النتيجة هي نفسها دائمًا،
فأنت إذن تقوم في الواقع بإهدار الأداء،
لأنك تقوم بإعادة حسابها
في كل تكرار داخل الحلقة.
وبدلًا عن ذلك، احسب واحفظ
نتائج هذا الاستنتاج خارج الحلقة،
ثم اسمح للأجزاء الداخلية للحلقة
بالرجوع إلى تلك النتائج المخزنة مؤقتًا.
السبب في حبي الشديد للإرسال في دفعات،
وللتخزين المؤقت
هو أن جميع تحسينات الأداء الرائعة
التي يمكن أن تفكر فيها،
بما فيها التحسينات
التي تناولناها في هذه الدورة،
هي تنويعة من هاتين التقنيتين الأساسيتين.
وإن أردت بجديّة أن تصبح
خبيرًا في الأداء،
فعليك أن تصبح محترفًا
في معنى التحكّم بفعالية
بقوة هاتين التقنيتين المذهلة.
إذن، هيا بنا فلنبدأ.
Quiero presentarles
mis dos técnicas favoritas de desempeño,
agrupamiento y almacenamiento.
Como ya lo mencionamos,
algunas funciones u operaciones
tienen una cantidad específica
de gastos generales relacionados con ellas
diferentes a los costos de desempeño
de la operación en sí misma.
Como cargar datos en la memoria
antes de ejecutarla
o clasificar un grupo de valores
antes de hacer una búsqueda.
Si se ejecuta varias veces y los múltiplos
representan un gran número,
estos gastos generales se convertirán
en una carga para tu app.
El proceso de agrupamiento por lotes
soluciona este problema de desempeño
eliminando los gastos generales
por ejecución de estas operaciones.
Es como compartir un auto
en vez de conducir el tuyo.
Esto se ve con frecuencia en tu código
cuando tienes que preparar tus datos
antes de operar con él.
Ahora, digamos que la forma más eficaz
de encontrar un valor
en un conjunto es clasificarlo
y ejecutar la búsqueda binaria.
Para ser claros, esta en realidad
no es la forma más eficaz.
Solo síganme porque estoy tratando
de explicarles algo.
La manera más simple
de hacer esto es escribir una función
que en conjunto de valores
clasifique el conjunto y luego busque
para ver si el valor existe en él.
Ahora, esto puede estar bien
para cierto nivel de desempeño
pero digamos que tienes 10.000 valores
que quieres probar
y el tamaño del conjunto es de millones.
De repente, estás incurriendo en toneladas
de gastos generales por prueba
en forma de clasificación.
La respuesta es bastante clara.
Crear la versión clasificada del conjunto
y luego permitir
que los 10.000 valores sean probados
para la inclusión después de eso.
Esto es agrupamiento por lotes.
Factorizamos la operación que se repite
y la hicimos una vez.
Ahora, hay un concepto similar a este
conocido como almacenamiento en cache
que es la técnica de desempeño
más importante para comprender
principalmente porque maneja todo
en la tecnología moderna de computación.
Tu computadora, por ejemplo.
El RAM ofrece un lugar
para el almacenamiento de la información
que es más rápido de acceder
para la CPU que el disco duro.
Tomemos, por ejemplo, las redes
y la internet actual.
En el mundo hay enormes servidores
llamados centros de datos.
Su único fin es almacenar o guardar
el contenido que se usa con frecuencia
para que tu PC no tenga que alcanzar
un servidor ubicado a 12.000 millas
cuando tu amigo
en Egipto publique una foto.
Bueno, a menos que estés en Egipto.
Pero ya entiendes la idea.
En tu código, el lugar más común
para encontrar optimizaciones
de almacenamiento es donde los datos
se calculan varias veces
pero cuyos resultados siempre son iguales.
Por ejemplo, si estás en medio de un bucle
que estás calculando
los derivados de una matriz
de cuatro por cuatro
y ese resultado siempre da igual,
allí desperdicias desempeño
recalculando cada iteración del bucle.
En cambio, calcula y guarda los resultados
fuera del bucle
y deja que las partes internas del bucle
referencien el resultado guardado.
El motivo por el que me gustan
el agrupamiento y almacenamiento
es que cada mejora de desempeño
que puedas pensar
incluyendo las mencionadas en este curso,
es una variante efectiva
de estas dos técnicas básicas.
Si de verdad quieres convertirte
en un ninja del desempeño,
entonces será mejor que seas
un profesional en el aprovechamiento
del fantástico poder de estas técnicas.
Así que, comencemos.
Je tiens à vous présenter mes deux
techniques d'optimisation préférées,
le traitement par lot et la mise en cache.
Comme on l'a déjà dit,
certaines fonctions ou opérations
comportent une quantité
spécifique de surcharge intrinsèque
qui diffère de la surcharge
due à l'exécution de l'opération en soi.
Par exemple, réadresser des données
dans la mémoire avant leur exécution,
ou trier un ensemble de valeurs avant
d'y faire une recherche.
Lorsqu'on les exécute plusieurs fois,
ici « plusieurs » c'est de gros chiffres,
cette surcharge peut devenir un fardeau
pour l'exécution de votre application.
Le traitement par lot est le processus
qui corrige ce problème de performance
en essayant d'éliminer la surcharge
d'exécution de chaque opération,
un peu comme covoiturer au lieu d'avoir
chacun sa voiture, pour l'essence.
Cette pratique apparaît en codage
quand on doit « préparer » ses données
avant de les traiter concrètement.
Par exemple, disons que la meilleure façon
de trouver une valeur
dans un ensemble est de le trier
puis d'exécuter une recherche binaire.
Enfin, ce n'est pas vraiment
la plus efficace des méthodes,
mais restez avec moi,
je tente de m'expliquer.
La façon la plus « simple » ici
serait de coder une fonction qui,
avec une consigne et une valeur données,
trierait l'ensemble puis
chercherait à voir si la valeur y est.
Ça peut convenir
à certains niveaux de performances,
mais mettons qu'on ait
10 000 valeurs à tester,
et que la taille de l'ensemble
se compte en millions.
Tout d'un coup, on se retrouve
avec une tonne de surcharge par test
sous la forme du tri.
La réponse ici est assez claire.
Il faut créer une version triée
de tout l'ensemble mais une seule fois
et ensuite, tester les 10 000 valeurs
à inclure après ce point.
C'est le traitement par lot en action.
On factorise l'opération qui se répète
pour ne l'appliquer qu'une fois.
Un concept similaire à ça est en fait
la mise en cache,
c'est de loin la technique d'optimisation
la plus importante à comprendre,
notamment car elle dicte tout
dans la technologie informatique moderne.
Prenez votre ordinateur, par exemple.
La seule raison d'être de la mémoire vive,
c'est d'avoir un stock d'informations
qui soit plus rapide d'accès pour l'UC
que le disque dur.
Observez les réseaux et notamment
internet tel qu'il est actuellement,
il y a d'énormes entrepôts de serveurs ou
centres de données dans le monde entier.
Leur seul but est de stocker, de mettre
en cache, le contenu fréquemment consulté
pour que votre ordinateur n'ait pas
à joindre un serveur à 19 000 km d'ici
dès que votre ami en Égypte
publie une photo.
Sauf si vous y êtes déjà, bien sûr,
mais bon, on s'est compris.
Dans un code, le lieu le plus courant
où trouver une optimisation
pour de la mise en cache, concerne
les données calculées plusieurs fois,
mais dont le résultat
est toujours le même.
Par exemple, au beau milieu
d'une boucle que vous calculez
la dérivée d'une matrice carrée
d'ordre quatre,
si le résultat est toujours le même,
vous y perdez en performance,
puisque vous la recalculez
à chaque itération de la boucle.
Calculez et enregistrez les résultats
de la dérivation en dehors de la boucle
et la portion interne à la boucle n'aura
qu'à appeler ce résultat mis en cache.
Si j'aime le traitement par lot
et la mise en cache, c'est parce que
quasiment toutes les optimisations
de performances imaginables,
y compris celles
dont on parlera dans ce cours,
ne sont que des variantes
de ces deux techniques de base.
Et si vous voulez vraiment
devenir un ninja de la performance,
alors il vaut mieux devenir un pro
de ce que signifie exploiter
la puissance impressionnante
de ces techniques.
Donc, commençons.
Saya ingin memperkenalkan dua
teknik kinerja favorit saya,
batching dan caching.
Seperti sudah kita bicarakan,
beberapa fungsi atau
operasi memiliki jumlah overhead
tertentu
yang berbeda dengan biaya kinerja
operasi itu sendiri.
Misalnya, memuat data ke tempat baru dalam
memori sebelum mengeksekusinya,
atau menyortir seperangkat nilai sebelum
melakukan pencarian melaluinya.
Ketika dijalankan beberapa kali, dalam
kelipatan sangat besar,
overhead ini bisa menjadi beban kinerja
yang amat besar untuk aplikasi Anda.
Batching adalah proses memperbaiki
masalah kinerja ini
dengan mencoba mengeliminasi overhead
per eksekusi operasi ini.
Kita seolah pakai mobil bersama, bukan
mengemudi sendiri, hingga hemat bensin.
Ini paling sering terlihat pada kode
di saat Anda harus mempersiapkan data
sebelum benar-benar mengoperasikannya.
Katakanlah, cara paling efisien
untuk menemukan nilai
yang ada di rangkaian adalah mengurutkannya,
lalu menjalankan pencarian biner.
Sebenarnya, ini bukanlah
cara paling efisien,
tapi bersabarlah, saya coba
jelaskan di sini.
Cara tersederhana untuk melakukan itu
adalah menulis fungsi yang
dengan 1 rangkaian & nilai,
akan menyortir rangkaian dan memeriksa
apakah nilai itu ada di dalamnya.
Ini mungkin tidak masalah untuk
beberapa tingkat kinerja tetapi
katakanlah Anda punya 10.000 nilai
yang ingin diuji,
dan ukuran rangkaian ini jutaan.
Tiba-tiba Anda menimbulkan banyak
overhead per pengujian
dalam bentuk pengurutan.
Jawabannya cukup jelas.
Anda harus membuat versi urut
dari rangkaian itu sekali dulu,
lalu mengizinkan 10.000 nilai itu diuji
untuk diikutsertakan setelahnya.
Ini yang dimaksud batching dalam tindakan.
Kita perkirakan operasi yang berulang
dan menyelesaikannya sekali dulu.
Sebenarnya ada konsep serupa yang
dikenal sebagai caching, dan
sejauh ini merupakan teknik kinerja
terpenting yang dapat Anda pahami,
terutama karena teknik ini menggerakkan
semua hal dalam teknologi komputer modern.
Komputer Anda, misalnya.
Inti dari perangkat keras RAM adalah
memberi tempat untuk menyimpan informasi
yang bisa diakses lebih cepat oleh CPU
daripada hard drive.
Atau jaringan dan internet modern
misalnya,
gudang besar server yang disebut
pusat data ada di seluruh dunia.
Tujuannya hanya menyimpan atau memasukkan
konten yang sering diakses cache
agar komputer tak harus menghubungi server
sejauh 12.000 mil setiap kalinya,
tiap teman Anda di Mesir mengeposkan gambar.
Kecuali jika memang Anda di Mesir.
Anda pasti paham maksud saya, kan?
Dalam kode program Anda, titik terumum
yang dapat dioptimalkan untuk
caching terkait dengan data yang
dikalkulasi beberapa kali, tapi
hasilnya selalu sama.
Misalnya, jika Anda berada di tengah
loop yang sedang mengkalkulasi
turunan dari matriks empat kali
empatnya, dan
hasilnya selalu sama, maka Anda
membuang-buang kinerja,
dengan menghitung ulang untuk setiap
perulangan loop itu.
Sebaiknya, hitung dan simpan hasil turunan
di luar loop, dan
biarkan bagian dalam referensi loop yang
menyimpan hasilnya.
Saya sangat suka batching dan
caching karena hampir
setiap peningkatan kinerja yang
dapat Anda pikirkan,
termasuk yang kita bicarakan
dalam latihan ini,
adalah varian efektif dari dua
teknik dasar itu.
Dan jika Anda serius menjadi
pakar kinerja,
Anda sebaiknya menjadi profesional
dalam memanfaatkan
kehebatan yang luar biasa dari teknik ini.
Jadi, mari kita mulai.
私のお気に入りのパフォーマンス・テクニックを2つ
ご紹介します
バッチングとキャッシングです
すでに説明したとおり
機能やオペレーションにはそれらに関連するオーバーヘッドの
特定の量があるものがあり
オペレーション自体のパフォーマンス・コスト
とは異なります
たとえば実行前に メモリーの新しい場所に
データをロードすることです
または検索を行う前に一連の値をソートすることです
複数回実行する時
この回数がかなり多いと
このオーバーヘッドはアプリにとって
深刻なパフォーマンスの負荷となります
バッチングはこのパフォーマンスの問題を直すプロセスです
これらのオペレーションの実行オーバーヘッドごとに
削除を試みます
ガソリンの節約のためにみんながそれぞれ車に乗る代わりに
共有するようなものです
これは 実際に作動させる前にデータを準備する必要のある
コードに
よく見られます
たとえばセットに存在する値を見つける
最も効果的な方法が
ソートし そこで二分探索を実行することだとします
明確にすると
これは実際には最も効果的な方法ではありません
しかし強調したいことがあるので
このまま聞いてください
とにかく最もシンプルな方法は
機能を書くことです
セットと値を与え
セットをソートして検索して値が存在するか
見つける機能です
これはあるパフォーマンスレベルでは
いいかもしれませんが
たとえばテストしたい値が10,000
あるとします
セットのサイズが億単位だとします
テストごとに突然大量のオーバーヘッドを
ソートの形式で
負うことになります
ここでの答えは明確です
ソートしたバージョンのセットを作成したい
そして
10,000のすべての値をそのポイントの後に
テストします
これが作動中のバッチングです
くり返されもう一度行うオペレーションを
取り除きました
これと同様のものはキャッシングとして知られるコンセプトで
圧倒的に最も重要なパフォーマンス・テクニックなのです
その主な理由は最新のコンピューター・テクノロジーで
すべてを作動させるからです
たとえば手元のコンピューターを取ってみてください
RAMハードウェアの全ポイントは情報を保存する
場所を提供することです
ハードドライブより速くCPUにアクセスします
またはネットワーキングや
最新のインターネット自体を見てください
データ・センターと呼ばれる巨大なサーバーの倉庫が
世界中に存在します
それらの唯一の目的は頻繁にアクセスされた内容を保管または
キャッシュし
コンピューターが毎回19,200キロも離れたサーバーを
ヒットしなくてもいいようにするためです
エジプトにいる友達が写真を投稿します
もちろん エジプトにいなければ
話のポイントが分かりますよね
コードにおいてキャッシングの最適化を見つけられる
最も一般的な場所は
複数回算出されたデータに関連していますが
結果はいつも同じです
たとえば算出しているループの
真ん中にいるとします
4 x 4マトリクスの微分係数
そしてその結果はいつも同じで
実際パフォーマンスを無駄にし
そのループの各反復のために
再計算します
代わりに計算してその微分の結果をループの外に保存します
ループ基準の内側の部分に
結果をキャッシュさせます
バッチングとキャッシングが好きな理由は
思いつく限りのほとんどすべてのパフォーマンス改善が
可能だからです
そこにはこのコースで話したものも含まれます
これら2つの基本テクニックの相違です
あなたは真剣にパフォーマンス忍者になろうとしています
これらのテクニックの素晴らしい力を利用し
プロになるほうがいいでしょう
では始めましょう
제가 가장 좋아하는 성능 향상 기법을 2개 소개할게요
배칭과 캐싱이에요
이미 얘기했던 내용이지만
일부 함수와 연산자들은 일정량의 오버헤드를 가지는데
실제 연산에 필요한 성능과는 다릅니다
예를 들어 데이터를 처리하기 전에
새로운 저장공간에 옮기는 시간이나
검색을 하기 전에 정렬하는 시간을 말하는 겁니다
이런 함수와 명령을 정말 많이 반복할 때
오버헤드는 애플리케이션 속도에 매우 큰 영향을 미쳐요
배칭은 이런 성능 문제를 해결하는 절차입니다
실행할 때마다 걸리는 오버헤드를 줄여서 말이에요
각자의 차를 운전하기 보다 카풀을 해서 기름값을 아끼는 것과 비슷해요
배칭은 데이터를 ‘준비’시키는 단계에서 가장 많이 접합니다
데이터를 실제로 사용하기 전에 말이에요
예를 들어 집합에서 특정 값을 찾는 가장 효율적인 방법은
집합을 정렬한 후 이진 탐색을 하는 것이라고 가정해보세요
잠시만요 물론 이게 실제로 가장 효과적인 방법은 아니에요
그래도 속는 셈 치고 들어주세요
드리고 싶은 말이 있어서 그래요
어쨌든 가장 쉬운 방법은 함수를 작성하는 겁니다
집합과 특정 값이 주어지면
집합을 정렬한 후 검색을 해서
해당 값이 존재하는지 확인하는 겁니다
원하는 성능 수준에 따라 이 방법도 충분할 수 있어요
하지만 찾고 싶은 값이 1만 개 있고
집합은 몇백만 개의 값으로 이루어졌다고 생각해보세요
순식간에 문제가 바뀌어
매번 검색을 수행할 때마다 엄청난 오버헤드가 생겨요
정렬을 하기 때문에 말이죠
해결책은 간단해요
집합을 한 번만 정렬해서 보관하고
찾고 싶은 1만 개의 값을 정렬된 집합에서 찾는 겁니다
이것이 바로 배칭입니다
반복되는 계산을 찾아내고 한 번만 실행하는 거예요
배칭과 비슷한 캐싱이라는 개념도 있는데요
캐싱은 알고 계셔야 할 성능 개념 중 단연 가장 중요한 개념입니다
최근 컴퓨터 기술은 전부 캐싱에 의존하기 때문이죠
여러분의 컴퓨터를 보세요
RAM이 존재하는 이유는
CPU 접근시간이 더 빠른 저장 공간을 제공하기 위해서입니다
하드 드라이브보다 말이에요
아니면 네트워킹과 요즘 인터넷을 보세요
데이터 센터라고 부르는 거대한 서버 창고들이 세계 곳곳에 존재하는데
데이터 센터의 유일한 목적은 자주 사용하는 콘텐츠를 저장해서
여러분의 컴퓨터가 2만 km 떨어져 있는
서버까지 연결하지 않아도 되게 하는 거예요
이집트에 있는 친구가 사진을 올릴 때마다 말이에요
물론 여러분이 이집트에 계시면 상황이 다르지만...
제가 무슨 말을 하고 싶은지 아시겠죠?
그럼 여러분이 캐싱을 사용할 가장 기본적인 경우는
여러 번 반복하는 계산의 결괏값이
매번 같을 때에요
예를 들어 루프 안에서
4x4 매트릭스의 행렬식을 계산하는데
매번 계산된 값이 같다면
해당 루프를 반복할 때마다
같은 계산을 반복해 자원을 낭비하는 겁니다
대신 행렬식 값을 계산하고 루프 밖에 저장을 해 놓은 다음
루프에서 캐싱 된 값을 참조하게 해주세요
제가 배칭과 캐싱을 너무나도 사랑하는 이유는
여러분이 생각해낼 수 있는 모든 성능 향상 방법은
물론 이 강의에서 언급한 방법을 포함해서요
사실상 이 2개의 기술을 변경한 것뿐이에요
그리고 여러분께서 정말로 성능 고수가 되고 싶으시다면
알맞게 활용하실 줄 아셔야 해요
이 기술의 엄청난 위력을 말이죠
그럼 시작해봅시다
Eu quero lhe apresentar as minha duas
técnicas de desempenho favoritas,
batching e caching.
Como já falamos, algumas funções
ou operações
têm uma quantidade específica de
sobrecarga envolvida
que é diferente dos custos
do desempenho da operação em si.
Por exemplo, carregar dados em um novo
local na memória antes de executá-la,
ou ordenar um conjunto de valores
antes de fazer uma pesquisa por ela.
Quando executada múltiplas vezes,
onde múltiplas são mesmo muitas,
esta sobrecarga pode causar um sério
problema de desempenho para o seu app.
Batching é o processo de
reparar este problema de desempenho
tentando eliminar a sobrecarga
pela execução destas operações,
como dividir um carro em vez de cada um
conduzir sozinho, poupando combustível.
Isto é o mais comum de se ver em um código
onde você tem de preparar seus dados
antes de realmente operar nele.
Agora, por exemplo, digamos que a forma
mais eficiente de encontrar um valor
existente num conjunto é ordenar ele, e
depois executar uma pesquisa binária nele.
Agora, espere, na verdade, esta não é
a forma mais eficiente,
mas fique comigo,
estou tentando demonstrar algo.
Bem, a forma mais simples de fazer isto
seria escrever uma função onde,
dado um conjunto e um valor,
vai ordenar o conjunto e depois pesquisar
para ver se o valor existe nele.
Agora, isto pode funcionar em
alguns níveis de desempenho,
mas, digamos que você tem
cerca de 10.000 valores que quer testar,
e, o tamanho do conjunto
é na ordem dos milhões.
Subitamente, você incorre em
muitas sobrecargas por teste
na forma da ordenação.
A resposta aqui é muito clara.
Você iria querer criar uma versão
ordenada do conjunto uma vez,
e depois permitir que os 10.000 valores
sejam testados para inclusão após isso.
Isto é batching em ação.
Nós fatoramos a operação que
é repetida e fazemos isso uma vez.
Agora, semelhante a isso é
um conceito conhecido como caching
e que é de longe a mais importante técnica
de desempenho que você pode enterder,
principalmente porque ela dirige tudo
na tecnologia moderna de computadores.
Considere seu computador, por exemplo.
O objetivo da sua RAM é fornecer
um lugar para armazenar informação
que é mais rápida de acessar
pela CPU do que pelo HD.
Ou considere a rede, e
olhe para a internet moderna,
enormes armazéns de servidores chamados
data centers existem em todo o mundo.
Sua única finalidade é armazenar em cache
conteúdo acessado com frequência
para que seu computador não tenha de acessar
um servidor a 12.000 milhas de distância
cada vez que seu amigo no Egito
posta uma foto.
Bem, a não ser, claro, que você esteja
no Egito, mas você percebeu a ideia.
Agora, em seu código, o lugar mais comum
onde você pode encontrar otimizações
para caching tem a ver com dados que
são calculados múltiplas vezes,
mas, o resultado é sempre o mesmo.
Por exemplo, se você está no meio
de um loop onde está calculando
a derivada de uma matriz
quatro por quatro,
e esse resultado é sempre o mesmo, então
você está desperdiçando desempenho,
recalculando o mesmo em
cada iteração desse loop.
Em vez disso, calcule e salve os
resultados dessa derivação fora do loop,
e depois deixe as porções interiores do loop
acessar os resultados de referência.
A razão porque adoro batching
e caching é porque
quase qualquer melhoria de desempenho
que você possa pensar,
incluindo as que estamos
falando neste curso,
é efetivamente uma variação
destas duas técnicas básicas.
E se você quer mesmo
se tornar um ninja do desempenho,
então é melhor se tornar um pro
no que significa alavancar
o imenso poder destas técnicas.
Então, vamos começar.
Я хочу рассказать вам о моих любимых
методах улучшения производительности:
это группировка и кэширование.
Как мы уже обсудили,
некоторые функции
или операции подразумевают
определенные расходы ресурсов,
в дополнение к ресурсам
на непосредственное их исполнение.
Например, загрузка данных перед
их исполнением в новый участок памяти
или сортировка набора значений
перед осуществлением в них поиска.
Когда операции исполняются много раз,
где много — это очень большое число,
эти издержки могут серьезно повлиять
на производительность вашего приложения.
Группировка позволяет
решить эту проблему
путем устранения издержек
на каждое исполнение,
как несколько человек экономят на бензине,
когда едут все вместе на одной машине.
Это часто встречается в тех участках кода,
где необходимо подготовить данные
до того, как их можно будет использовать.
Давайте предположим, что наиболее
эффективный способ найти значение
в множестве — это проделать сортировку,
а затем бинарный поиск.
Это, конечно, не самый
эффективный способ,
но дослушайте меня:
я пытаюсь кое-что объяснить.
Проще всего для этого будет
написать функцию,
которая, имея множество и значение,
отсортирует множество, а затем
проверит, есть ли в нём это значение.
В некоторых случаях
это может сработать,
но если у вас, скажем, 10 000 значений,
которые вы хотите проверить,
а счёт элементов во множестве
идет на миллионы,
то вы уже расходуете
уйму ресурсов на каждую проверку
из-за сортировки.
Решение здесь довольно простое.
Вам нужно создать один раз
отсортированный вариант множества,
после чего тестировать на вхождение
все эти 10 000 значений.
Так работает группировка.
Вынеся за скобки повторяющуюся операцию,
мы делаем её всего один раз.
Сходный принцип лежит в основе
концепции кэширования.
Это безусловно самый важный метод
улучшения производительности,
в основном потому, что он лежит в основе
всех современных компьютерных технологий.
Возьмём, например, ваш компьютер.
Весь смысл оперативки — предоставить
место для хранения информации,
доступ к которому процессор
получает быстрее, чем к жёсткому диску.
Или возьмём компьютерные сети
и вообще современный интернет:
по всему миру находятся огромные
хранилища серверов — дата-центры.
Единственная их функция — хранить,
или кэшировать, часто вызываемый контент,
чтобы ваш компьютер не обращался
к серверу за 20 000 км каждый раз,
когда ваш друг из Египта
постит фото.
Кроме случаев, когда вы сами в Египте.
Но вы, наверняка, уловили мою мысль.
Оптимизация кода для кэшинга
обычно происходит в тех местах,
где данные рассчитываются
много раз,
но результат всегда
получается одинаковый.
Например, если вы находитесь
в середине цикла, который рассчитывает
определитель матрицы 4x4
с одним и тем же результатом,
вы теряете в быстродействии
при каждом прохождении
этого цикла.
Вместо этого, рассчитайте определитель
вне цикла, сохраните его,
а затем сделайте отсылку из цикла
к кэшированному результату.
Причина, по которой я так люблю
группировку и кэширование,
состоит в том, что почти все возможные
улучшения производительности,
в том числе обсуждаемые
в этом курсе,
по сути являются вариацией
этих двух базовых методов.
И если вы всерьёз хотите стать
гуру по вопросам быстродействия,
вам нужно освоить
хитрости использования
этих удивительно мощных методов.
Что ж, приступим.
Favorim olan iki performans
tekniğini, size tanıtmak istiyorum:
yığınlama ve ön belleğe alma.
Daha önce de üzerine
konuştuğumuz gibi, bazı işlevler
veya işlemler, yürütmenin kendisine ait
performans maliyetlerinden farklı olan
belirli miktarda ilave yükler getirir.
Örneğin, yürütülmeden önce, verilerin
hafızada yeni bir yere yüklenmesi
ya da üzerinden bir arama yapılmadan önce,
bir değerler dizinin sıralanması.
Birden fazla defa yürütüldüğünde
ve her yürütme gerçekten büyük sayılarla
gerçekleştirildiğinde, uygulamanızın
performansı üzerinde ciddi bir yük oluşur.
Yığınlama, her bir işlemin yarattığı
yükü saf dışı bırakarak,
bu sorunu çözer. Yani, herkesin kendi
arabasını kullanması yerine tek bir
arabayı kullanması ve benzinden tasarruf
etmesi gibidir.
Bu, kodunuzu yürütmeden önce,
veri hazırlama aşaması sırasında
kodunuzda sıklıkla görülür.
Örneğin, bir dizide var olan
bir değeri bulmanın en verimli yolu,
onu sıralamak ve sonra da
ikili arama yürütmektir.
Pekala, bekleyin, bu hiç de
en verimli yol değildir,
ama beni takip etmeye devam edin,
bir yere varacağım.
Bir dizi ve işlev veriliyken,
bunu yapmanın en basit yolu,
diziyi sıralamak ve
sonra da değerin var olup olmadığını
görmek için, arama yapmaktır.
Bu, bazı performanslar için
kullanışlı olabilir
fakat diyelim ki test etmek istediğiniz
10.000 tane değer var
ve dizinin değeri milyonlara varıyor.
Sıralama formunda, her bir test için
birdenbire devasa bir yükle
karşı karşıya kalırsınız.
Burada cevap açıktır.
Dizinin sıralı versiyonunu bir kerede
yaratmak istiyorsunuz ve
sonra, 10.000 değerin, kapsama
için test edilmesine izin veriyorsunuz.
İşte bu, yığınlamadır.
tekrar edilen yürütmeyi, öğelerine
ayırdık ve bunu bir kerede yapıyoruz.
Ön belleğe alma olarak bilinen kavramda
buna benzerdir ve bilmeniz gereken en
önemli performans tekniğidir
çünkü modern bilgisayar
teknolojisindeki her şeyin
arkasında yatmaktadır.
Örneğin, bilgisayarınız.
RAM donanımının tüm yaptığı, bilgileri
depolamanız için yer sağlamaktır.
Bilgilere, sabit diskten
daha hızlı erişim sağlar.
Ya da ağlara ve
modern internetin kendisine bakın,
veri merkezleri denen sunucu
depoları tüm dünyada var.
Bunların tek amacı, sık erişilen içeriği
depolamak ya da ön belleğe almaktır.
Böylece bilgisayarınız, Mısırdaki
arkadaşınız her resim gönderdiğinde,
20.000 km ötedeki sunucuya
ulaşmak zorunda kalmaz.
Pekala, bu Mısır örneğiyle,
ne demek istediğimi anlamışsınızdır.
Kodunuzda, ön belleğe alma için
optimizasyonlar bulacağınız en alışıldık
yer, çok defa hesaplanan
verilerle ilgilidir,
fakat sonuç her zaman aynıdır.
Örneğin, eğer dörde dört matriksin
türetmesini hesapladığınız döngünün
ortasında iseniz ve sonuç aynı ise,
bu demektir ki, döngünün her bir
tekrarı için ayrı hesap yaparak,
performansı heba
ediyorsunuz.
Bunun yerine, döngü dışındaki türetmenin
sonuçlarını hesaplayın ve kaydedin ve
döngünün iç kısımlarının, ön belleğe
alınan sonuçlara başvurmasına izin verin.
Yığınlama ve ön belleğe almayı
sevmemin nedeni, bu derstede üzerine
konuştuklarımız dahil,
düşünebileceğiniz her türlü
performans gelişiminin,
bu iki temel tekniğin
bir varyantı olmasıdır.
Bir performans ninjası olma
konusunda ciddiyseniz,
bu güçlü tekniklerden
yararlanma konusunda
uzmanlaşmanız iyi olur.
Hadi başlayalım.
Tôi muốn giới thiệu các bạn
hai kỹ thuật hiệu năng tôi ưng ý,
định lô và lưu bộ nhớ đệm.
Như từng nói qua, một vài hàm
hay thao tác hàm
phát sinh định mức chi phí,
khác hẳn chi phí vận hành thực tế
của chính thao tác hàm đó.
Ví dụ, khi tải dữ liệu qua vị trí mới
trong bộ nhớ trước khi thực thi,
hay sắp xếp bộ giá trị
trước khi rà soát tập hợp.
Khi dữ liệu thực thi nhiều lần,
và khi bội số lần thực thi cao,
chi phí này trở thành gánh nặng
hiệu suất cho ứng dụng của bạn.
Định lô là quy trình khắc phục
sự cố vận hành này,
bằng cách cắt chi phí
thực thi từng hoạt động này,
giống như đi chung xe thay vì
lái xe riêng, để tiết kiệm xăng.
Định lô thường gặp trong bộ mã
khi cần chuẩn bị dữ liệu
trước thực thi.
Ví dụ, cách hữu hiệu nhất để tìm giá trị
trong tập hợp là phân loại,
rồi tìm kiếm nhị phân.
Khoan, để nói rõ hơn, thực ra
đây không phải cách hiệu quả nhất.
khoan nhé,chờ tôi chút,
tôi đang cố giải thích.,
Cách đơn giản nhất để thực hiện là viết
một hàm bằng tập hợp và giá trị cho sẵn,
nó sẽ phân loại rồi kiểm tra
xem giá trị có ở trong tập hợp không.
Thao tác này có thể hữu hiệu
ở vài mức độ vận hành
nhưng nếu bạn có, ví dụ,
10.000 giá trị cần kiểm tra,
tập hợp lên tới vài triệu phần tử.
Tự khắc phát sinh nhiều chi phí
để kiểm tra từng cái một
theo phân loại này.
Đáp án ở đây khá rõ ràng.
Ta sẽ tạo bản sao đã phân loại
của tập hợp một lần,
rồi kiểm tra 10,000 giá trị
cần đưa vào trong tập hợp.
Đó là cách định lô.
Loại bớt thao tác lặp lại,
chỉ thao tác một lần thôi.
Tương tự là khái niệm
lưu trữ bộ nhớ đệm,
và cho đến nay, đây là kỹ thuật hiệu năng
quan trọng nhất bạn cần biết,
vì nó chi phối mọi hoạt động
trong công nghệ điện toán hiện đại.
Lấy ví dụ máy tính của bạn.
Điểm mấu chốt của bộ nhớ RAM
là làm trạm lưu trữ thông tin
cho CPU lấy dữ liệu nhanh hơn,
so với khi lấy từ ổ cứng.
Một ví dụ khác là mạng xã hội,
cũng như mạng internet hiện nay,
có các kho máy chủ khổng lồ
là trung tâm dữ liệu khắp thế giới.
Mục đích duy nhất là lưu trữ
bộ nhớ đệm nội dung thường truy cập.
sao cho máy tính không cần tìm
máy chủ ở xa cách 12.000 dặm.
mỗi khi bạn của bạn ở Ai Cập đăng ảnh.
Trừ phi bạn đang ở Ai Cập,
tuy nhiên, bạn hiểu vấn đề rồi.
Trong bộ mã, thường thì có thể
tìm được kỹ thuật tối ưu hóa
lưu trữ bộ nhớ đệm khi xử lý
nhóm dữ liệu cần nhiều lần đếm,
nhưng kết quả cho ra luôn giống nhau.
Ví dụ, trong một vòng lặp
đang được tính toán,
đạo hàm ma trận 4x4,
kết quả luôn tương đồng,
nên bạn sẽ lãng phí hiệu suất,
nếu tính toán lặp lại chỉ số này
ở đầu mỗi bước lặp.
Thay vì vậy, tính toán và lưu
kết quả đạo hàm ngoài vòng lặp một lần,
rồi nội hàm tham chiếu vòng lặp
sẽ lưu trữ bộ nhớ đệm kết quả.
Tôi thích định lô và lưu bộ nhớ đệm
vì khả năng cải thiện hiệu suất
tốt vô cùng của chúng.
Những kỹ thuật đang nói đến
trong khóa học này,
chẳng qua là biển thể của
hai kỹ thuật cơ bản này.
Nếu bạn nghiêm túc muốn thành
siêu nhân về quản lý hiệu năng,
thì bạn nên chuyên nghiệp hơn
về kỹ thuật thúc đẩy hiệu năng
bằng cách sử dụng
hai kỹ thuật rất mạnh này.
Nào, bắt đầu thôi.
我想向你们介绍我最喜欢的两个性能技术
批处理(batching)和缓存(caching)。
前面我们已经说过一些函数和运算
需要非常大的资源开销。
这也会影响计算性能。
例如,在执行之前把数据载入特定的内存区域,
或者,在搜索之前对数值集进行排序。
在执行多次之后,而且次数确实是个很大的数字。
资源开销将会严重影响应用程序的性能。
批处理是可以帮助解决这种性能问题,
它消除每个运算的独立执行开销,
好像是所有人都开一辆车,
而不是每个都开一辆,从而节省汽油。
这种情况最常见于在执行运算之前,
你需要准备数据。
例如,在查找集合中的值时,
最有效的方法是进行排序,
然后进行二分法搜索等等。
有一点必须弄清楚,这并不是最效的方法。
这只是举一个例子而已,
最简单的方法是写一个函数,
提供一个集合和一个值。
对集合进行排序,
然后查看值是否存在于集合之中。
对于某些性能要求来说,
这样做是可以的。
但是,如果有10,000个值,
而且总共需要数百万组数据,
排序所花费的时间,
将会增加很多倍,
答案很明确。
对这组数据一次性完成排序,
然后查找所有10,000个值,
并不是明智的方法。
这时就需要用到批处理,
我们找到重复的运算,
找到之后,进行批处理。
缓存是与批处理相似的概念。
这也是目前为止,
你能理解的最重要的性能技术。
这项技术全面地推动现代计算机科学的发展。
以计算机为例,内存的作用是用来存储信息,
让CPU能够更快地访问数据,
其速度远快于访问硬盘数据。
或者以网络为例,
世界各地存在大型服务器仓库,
它们被称为数据中心。
它们的作用是存储或缓冲被频繁访问的内容。
这样,你的计算机就不必
每次都访问远在12,000英里之外的服务器。
你在埃及的朋友可能在这个服务器上发布了一张图片。
当然,你知道,如果你在埃及,
这样的缓存服务器可能就没有什么意义。
但是你已经明白其中的道理。
以代码为例,
最常见的缓存优化通常涉及多次计算。
但是结果始终相同的数据,
例如,在循环计算中,
你计算一个4x4数列的导数,
结算始终是相同的,
每次重新计算循环迭代,
实际是在浪费计算机资源,
相反,在循环流程的外部存储导数的结果,
并让你的内部循环语句引用缓存结果,
可以极大地提升效率。
我之所以喜爱缓存和批处理,
是因为它们能够改善所有你能够想到的性能问题,
包括我们在本课程中提到的问题,
这是两个非常有效的技术。
如果你想成为一名性能专家,
你最好能够熟练掌握这两项强大的技术。
让我们开始。
我想向你介紹
我最喜歡的兩個效能技巧
分批與緩存
如同我們已經談過的
有些函數或
作業有著一個與作業本身的效能成本
不同的特定數量的
開銷包含在它們裡面
舉例來說 在執行一個數據之前
加載它到記憶體中一個新的地方
或者在搜索一組數據前
先行進行排序
在執行數次之後
這裡的數次指的是一個很大的數字
這個額外的開銷會對你的應用程式成為一個
很大的效能負擔
分批是一個改善這項效能問題的過程
藉著減少這些作業每次作業的開銷
類似於藉著共乘一台車而非每個人都
自行開車 可以達到省油的效果
這最經常出現在你的代碼中
當你在操作之前
需要先行準備你的數據
舉例來說 我們假設在一組數據中
最有效的尋找方法是藉著排序
然後執行一個二進制搜尋
等等 先說明
這並不是實際上最有效的方法
但還是聽我講完
我在嘗試闡述一個重點
不論如何 做這件事最簡單的方法就是
在有一組以及一個值的情況下
寫出一個排序並搜尋以確認
該值是否存在的函數
這可能對某些效能等級是沒問題的
但若你有10,000個值你想測試
並且有數百萬組的情況下
忽然之間 你的每個測試
都在以排序的方式
承擔著很多的開銷
這裡的答案淺而易顯
你將會想要建立一組排序過的版本
然後能夠將10,000個值都能包含在測試之內
這就是分批的行為
我們將重複進行的作業分解出來
並一次完成
跟這很像的還有一個概念叫緩衝
而且這是到目前為止你所能理解的
最重要的技巧
最主要的原因是因為它是藉著
現代電腦科技驅動一切
用你的電腦舉例來說
你的RAM的存在意義就是為了提供一個地方儲存資訊
並能讓CPU比硬碟更快的讀取該資料
或者以網路來說
看看現代網路本身
世界各地都存在著稱呼為數據中心的
巨型伺服器倉庫
它們的唯一目的是在儲存
或緩衝經常讀取的內容
讓你的電腦不用因為你的朋友
每張貼一張照片
就必須每次訪問12,000英里遠的伺服器
當然 除非你就在埃及的話啦
但你懂我的意思的
現在在你的代碼中
你最常能找到為緩衝進行優化的地方
是在必須計算過數次
t
但結果每次都相同的數據中
舉例來說
你在一個計算四乘四矩陣的衍生物的迴圈中
並且結果永遠是相同的
在該循環的每次迭代都重新計算它
那實際上你就是在浪費效能
取而代之的是
在迴圈外計算並儲存該衍生物的結果
並讓你的迴圈的內部參考該緩衝結果
我這麼愛分批以及緩衝的原因是
因為幾乎你所能想到的效能進步方法
包含我們在這個課程中所提到的
都是這兩個基礎技巧的延伸
而且如果你是認真的想要成為一位效能達人
那你最好能夠將這些技巧的運用
極大化
那麼 就讓我們開始吧