Спочатку дозволю собі навести дві цитати форумчан з інших тем.
Якщо Ви не вмієте програмувати ні на чому, крім Бейсика, і не знаєте, як распараллеливать процеси обчислення, то це не означає, що інші теж не знають і не вміють. А якщо грамотно запрограмувати перебір, то варіантів цілком під силу звичайній сучасній персоналке, і вона все зробить за цілком прийнятний час.
[Повідомлення звернено до мене]
Зараз моя програма не використовує багатоядерність, тобто можна тільки запускати кілька програм за кількістю ядер процесора без збільшення часу роботи.
Очевидно, що в обох цитатах йдеться про розпаралелювання процесу обчислень в програмах, призначених для виконання на комп'ютерах з багатоядерними процесорами.
Хто може спробувати?
Nataly-Mak
У мене теж знань небагато.
Перше що скажу розрізняють 3 рівня розпаралелювання.
1) Між комп'ютерами
2) Між ядрами
3) паралелізм на рівні команд.
Для кожного рівня застосовують свої інструменти.
1) Між комп'ютерами. Мабуть найпростіший спосіб паралельної обробки даних. Припустимо у вас є комп'ютерний клас об'єднаної мережею. Ви просто копіюєте на комп'ютери дані і свою програму і запускаєте на виконання. Після отримуєте результат. Для планування таких робіт існує море програм. Якщо ви сроете кластер в інтернеті. То тут ще доводиться вирішувати завдання захисту даних і системи. А також те, що комп'ютери в інтернеті різні.
2) Паралелізм між ядрами. У комп'ютері багато обчислювальних блоків найбільші це центральний процесор (ЦП / CPU) і графічний процесор (ГП / GPU). Кожен процесор містить один або кілька ядер. Ядро можна розглядати, як окремий пристрій на якому можна запустити свій потік команд. Зазвичай не поділяють мультипроцесорний і мультиядерність.
Відмінність наявність загальної шини для доступу до спільної пам'яті.
Тут можна виділити два види систем SMP і NUMA.
Симетричне мультіпроцессірованіе (англ. Symmetric Multiprocessing, скорочено SMP) - архітектура багатопроцесорних комп'ютерів, в якій два і рідше більше двох однакових процесорів підключаються до загальної пам'яті. При доступі до загальної пам'яті вся шина блокується з цього одночасне читання або запис неможлива.
NUMA (Non-Uniform Memory Access - «нерівномірний доступ до пам'яті» або Non-Uniform Memory Architecture - «Архітектура з нерівномірною пам'яттю».
Архітектура в якій доступ до різних ділянок пам'яті має різну швидкість. Це пов'язано з розумним розподілом пам'яті, коли доступ до своєї пам'яті йде без блокування, а доступ до спільної з блокуванням.
Якщо розглядати ЦП. Те для розпаралелювання, коду зазвичай вирішується написанням паралельного коду для одного ядра і створенням декількох потоків. Зазвичай є такий код. Це вирішується на рівні мови.
CreatThead (Thead);
Thead.Do (function);
function - підпрограма яка буде виконуватися в декількох потоках.
Це найпримітивніший. Є більш розширені речі таке як OpenMP який полегшує написання.
Складного нічого немає. Тільки треба потренуватися щоб навчитися мислити паралельно.
Але піклуватися про доступ до пам'яті і блокування доводиться програмісту.
ДП (GPU) потужне обчислювальний пристрій. Сучасні ДП набагато продуктивніше ніж ЦП. Тому його цікаво задіяти для обчислень. Ще більш цікаво запустити один код одночасно на CPU і GPU. Для цих цілей використовують CUDA і ATIStreem і ін.
CUDA розробка NVIDIA, а ATIStreem розробка ATI. Так що запуск однакового коду на картах різних виробників скрутний. Потрібно переписувати. Правда я не в курсі останніх нововведень.
3) паралелізм на рівні команд.
Сучасні процесори мають мультіскалярную архітектуру. Кожне ядро зазвичай має кілька АЛУ (Арифметико-логічний пристрій). При певній організації даних і команд ядро може паралельно виконувати декілька команд. Ще є таке поняття як SIMD.
SIMD (англ. Single instruction, multiple data - одна команда, безліч даних, ОКМД) - принцип комп'ютерних обчислень, що дозволяє забезпечити паралелізм на рівні даних. Коли дані згруповані в двійки, четвірки, вісімки. І одна команда виконує одну операцію над даними, задіюючи 2,4,8 АЛУ.
А що, можна збільшити час виконання в кілька разів (всього при двох ядрах процесора)?
Так можна. Є відома формула закон Амдаля якщо відсоток витрат малий, то приріст можна отримати великий. З причини того що зазвичай центральний процесор містить 2-4 ядра, а кожне ядро 8,16. АЛУ. Графічний процесор має десятки, сотні, а топові тисячі АЛУ. В GPU АЛУ зазвичай умовно групуються на 4 рідше 8 ядер.
Якщо знаєте паскаль. І збираєтеся писати на фрі паскале / Delphi.
На жаль! Зараз не знаю. Дуже давно, коли працювала, Паскаль знала і писала на ньому програми.
Тепер, після багаторічної перерви, знаю тільки Бейсік (див. Саму першу квитанцію цитату)
Пишу на QBASIC. Колега svb знайшов для мене дуже хороший компілятор pb5 (до того працювала з інтерпретатором).
Написала під цей компілятор десятки програм побудови різних магічних квадратів, нічого, нормально будуються квадрати
// Використовувані типи даних
const mx = 43;
type
PNumbers = ^ TNumbers;
TNumbers = array [0..mx * mx-1] of int64;
TMatrix = array [0..mx-1, 0..mx-1] of int64;
type
TAInteger = array of integer;
procedure ViewSquare # 40; k: integer; ms: TMatrix; S: int64; p: boolean = false; a: boolean = false # 41 ;; overload;
procedure ViewSquare # 40; var F: TextFile; k: integer; ms: TMatrix; S: int64; p: boolean = false; a: boolean = false # 41 ;; overload;
procedure ViewNumbers # 40; k: integer; S: int64; A: TNumbers # 41 ;;
procedure ViewMatrix # 40; k: integer; A: TNumbers # 41 ;;
function GetCnk # 40; n, k: integer # 41;: int64;
procedure SetA # 40; var A: TNumbers; b: array of int64 # 41 ;;
procedure SetM # 40; n: integer; var M: TMatrix; b: array of int64 # 41 ;; overload;
procedure SetM # 40; n: integer; var M: TMatrix; b: array of integer # 41 ;; overload;
function toMatrix # 40; n: integer; A: TNumbers # 41;: TMatrix;
function CheckMS # 40; n: integer; m: TMatrix; var S: int64; var p, a: boolean # 41;: boolean;
procedure ToMatrixRosser # 40; n: integer; A: TNumbers; var M: TMatrix # 41 ;;
function isMagic # 40; n: integer; M: TMatrix; var S: int64; var p: boolean # 41;: boolean;
function isPMagic # 40; n: integer; M: TMatrix; S: int64 # 41;: boolean;
procedure RosserToMatrix # 40; n: integer; M: TMatrix; var A: TNumbers # 41 ;;
function isDifferent # 40; n: integer; M: TMatrix # 41;: boolean;
procedure SetAInteger # 40; a: array of integer; var ls: TAInteger # 41 ;;
procedure SetA # 40; var A: TNumbers; b: array of int64 # 41 ;;
var i: integer;
begin
fillchar # 40; A, sizeof # 40; A # 41 ;, 0 # 41 ;;
for i: = low # 40; b # 41; to high # 40; b # 41; do begin
A [i]: = b [i];
end;
end;
procedure ViewSquare # 40; k: integer; ms: TMatrix; S: int64; p: boolean = false; a: boolean = false # 41 ;;
var i, j. integer;
begin
write # 40; k, ': [' # 41 ;;
if p then write # 40; 'p' # 41 ;;
if a then write # 40; 'a' # 41 ;;
write # 40; ']:', S, ':' # 41 ;;
for i: = 0 to k-1 do
for j: = 0 to k-1 do begin
write # 40; ms [i, j] # 41 ;;
if # 40; i
writeln;
end;
procedure ViewSquare # 40; var F: TextFile; k: integer; ms: TMatrix; S: int64; p: boolean = false; a: boolean = false # 41 ;;
var i, j. integer;
begin
write # 40; F, k, ': [' # 41 ;;
if p then write # 40; F, 'p' # 41 ;;
if a then write # 40; F, 'a' # 41 ;;
write # 40; F, ']:', S, ':' # 41 ;;
for i: = 0 to k-1 do
for j: = 0 to k-1 do begin
write # 40; F, ms [i, j] # 41 ;;
if # 40; i
writeln # 40; F # 41 ;;
end;
procedure ViewNumbers # 40; k: integer; S: int64; A: TNumbers # 41 ;;
var i. integer;
begin
write # 40; k, ':' # 41 ;;
write # 40; S, ':' # 41 ;;
for i: = 0 to k-1 do begin
write # 40; A [i] # 41 ;;
if # 40; i
writeln;
end;
// Повертає кількість сполучень з n по k
// # 40; без урахування порядку проходження # 41;
// Cnk = n! / # 40; k! * # 40; n-k # 41;! # 41;
function GetCnk # 40; n, k: integer # 41;: int64;
var d: integer;
begin
d: = n-k;
result: = 1;
while n> d do begin
result: = result * n;
dec # 40; n # 41 ;;
end;
while k> 1 do begin
result: = result div k;
dec # 40; k # 41 ;;
end;
end;
function toMatrix # 40; n: integer; A: TNumbers # 41;: TMatrix;
var i, j: integer;
begin
fillchar # 40; result, sizeof # 40; result # 41 ;, 0 # 41 ;;
for i: = 0 to n-1 do begin
for j: = 0 to n-1 do begin
result [i, j]: = A [i * n + j];
end;
end;
end;
// Перевірка MS
function CheckMS # 40; n: integer; m: TMatrix; var S: int64; var p, a: boolean # 41;: boolean;
var i, j, l1, l2. integer;
S1: integer;
K: int64;
begin
p: = false;
result: = true;
// Вважаємо константу
S: = 0;
for j: = 0 to n-1 do S: = S + m [0, j];
// Перевірка по рядках
for i: = 0 to n-1 do begin
S1: = 0;
for j: = 0 to n-1 do S1: = S1 + m [i, j];
if S1 <> S then begin
result: = false;
exit;
end;
end;
// Перевірка по стовпцях
for i: = 0 to n-1 do begin
S1: = 0;
for j: = 0 to n-1 do S1: = S1 + m [j, i];
if S1 <> S then begin
result: = false;
exit;
end;
end;
// Перевірка двох діагоналей
S1: = 0;
for j: = 0 to n-1 do S1: = S1 + m [j, j];
if S1 <> S then begin
result: = false;
exit;
end;
S1: = 0;
for j: = 0 to n-1 do S1: = S1 + m [j, n-1-j];
if S1 <> S then begin
result: = false;
exit;
end;
// Перевірка пандіагональних
p: = true;
for j: = 1 to n-1 do begin
S1: = 0;
for i: = 0 to n-1 do S1: = S1 + m [i, # 40; j + i # 41; mod n];
if S1 <> S then begin
p: = false;
break;
end;
end;
if p then begin
for j: = n to 2 * n-1 do begin
S1: = 0;
for i: = 0 to n-1 do S1: = S1 + m [i, # 40; j-i # 41; mod n];
if S1 <> S then begin
p: = false;
break;
end;
end;
end;
// Перевірка асоціативності
K: = m [0,0] + m [n-1, n-1];
a: = true;
l1: = # 40; n-1 # 41; div 2;
for i: = 0 to l1 do begin
l2: = # 40; n-1 # 41; div 2;
if n mod 2 <> 0 then dec # 40; l2 # 41 ;;
for j: = 0 to l2 do begin
S1: = m [i, j] + m [n-1-i, n-1-j];
if S1 <> K then begin
a: = false;
break;
end;
end;
end;
end;
function isMagic # 40; n: integer; M: TMatrix; var S: int64; var p: boolean # 41;: boolean;
var i, j: integer;
S1: int64;
begin
result: = false;
// Обчислення суми
S: = 0;
for i: = 0 to n-1 do S: = S + M [0, i];
// Перевірка рядків
for i: = 0 to n-1 do begin
S1: = 0;
for j: = 0 to n-1 do begin
S1: = S1 + M [i, j];
end;
if S1 <> S then exit;
end;
// Перевірка стовпців
for i: = 0 to n-1 do begin
S1: = 0;
for j: = 0 to n-1 do begin
S1: = S1 + M [j, i];
end;
if S1 <> S then exit;
end;
// Перевірка двох діагоналей
S1: = 0;
for j: = 0 to n-1 do begin
S1: = S1 + M [j, j];
end;
if S1 <> S then exit;
S1: = 0;
for j: = 0 to n-1 do begin
S1: = S1 + M [j, n-1-j];
end;
if S1 <> S then exit;
p: = isPMagic # 40; n, M, S # 41 ;;
end;
function isPMagic # 40; n: integer; M: TMatrix; S: int64 # 41;: boolean;
var k, i: integer;
S1. int64;
begin
result: = false;
for k: = 0 to n-1 do begin
S1: = 0;
for i: = 0 to n-1 do begin
S1: = S1 + M [i, # 40; k + i # 41; mod n];
end;
if S1 <> S then exit;
end;
for k: = n to 2 * n-1 do begin
S1: = 0;
for i: = 0 to n-1 do begin
S1: = S1 + M [i, # 40; k-i # 41; mod n];
end;
if S1 <> S then exit;
end;
procedure ToMatrixRosser # 40; n: integer; A: TNumbers; var M: TMatrix # 41 ;;
var i, j, k, l. integer;
begin
for i: = 0 to n-1 do begin
for j: = 0 to n-1 do begin
k: = # 40; 3 * i + 2 * j # 41; mod n;
l: = # 40; 2 * i + j # 41; mod n;
procedure RosserToMatrix # 40; n: integer; M: TMatrix; var A: TNumbers # 41 ;;
var i, j, k, l. integer;
begin
for i: = 0 to n-1 do begin
for j: = 0 to n-1 do begin
k: = # 40; 3 * i + 2 * j # 41; mod n;
l: = # 40; 2 * i + j # 41; mod n;
procedure SetM # 40; n: integer; var M: TMatrix; b: array of int64 # 41 ;;
var i, j: integer;
begin
for i: = 0 to n-1 do
for j: = 0 to n-1 do begin
M [i, j]: = b [i * n + j];
end;
end;
procedure SetM # 40; n: integer; var M: TMatrix; b: array of integer # 41 ;;
var i, j: integer;
begin
for i: = 0 to n-1 do
for j: = 0 to n-1 do begin
M [i, j]: = b [i * n + j];
end;
end;
procedure ViewMatrix # 40; k: integer; A: TNumbers # 41 ;;
var i, j: integer;
begin
for i: = 0 to k-1 do begin
for j: = 0 to k-1 do begin
write # 40; A [i * k + j], '' # 41 ;;
end;
writeln;
end;
end;
// Перевірка всіх чисел матриці
// повертає true, якщо все числа різні
function isDifferent # 40; n: integer; M: TMatrix # 41;: boolean;
var i, j, k, l, c: integer;
D: int64;
begin
result: = true;
for i: = 0 to n-1 do begin
for j: = 0 to n-1 do begin
D: = m [i, j]; c: = 0;
for k: = 0 to n-1 do begin
for l: = 0 to n-1 do begin
if m [k, l] = D then begin
inc # 40; c # 41 ;;
if c> 1 then begin
writeln # 40; D # 41 ;;
result: = false;
exit;
end;
end;
end;
end;
end;
end;
end;
// a -> ls
procedure SetAInteger # 40; a: array of integer; var ls: TAInteger # 41 ;;
var i: integer;
begin
SetLength # 40; ls, high # 40; a # 41; -low # 40; a # 41; + 1 # 41 ;;
for i: = 0 to length # 40; ls # 41; - 1 do ls [i]: = a [i];
end;
У цій програмі не задіяна багатоядерність процесора.
Питання наступний: чи можливо і наскільки складно ввести в цю програму розпаралелювання всього процесу обчислень?
У мене, як уже писала, всього два ядра в процесорі. У мого колеги svb чотирьохядерний процесор. У одного товариша з іншого форуму восьміядерний процесор, і він готовий допомогти з виконанням програми, але сам распараллелить готовий код не може.
Або, може бути, щоб використовувати багатоядерність, треба писати новий код? Код, який написаний для одноядерного процесора, не годиться, переробити його під багатоядерний процесор складно або взагалі неможливо (?)
У тому вся!