• Главная
  • Карта сайта
Не найдено

Некошерним «goto»

  1. Не вірте данайців, «goto» приносить
  2. Що ще почитати на цю тему
  3. Відгуки

Оператор «goto» давно став темою релігійних суперечок. Одні стверджують, що без нього краще обійтися і взагалі він заважає верифікації програм. Інші кажуть про перше, що вони фанатики :

Одному Шановному Людині спало на думку, що програма повинна виконуватися так як вона читається, а goto - це зло. Цей окремий випадок, зручний при вирішенні певного класу задач, був потім доведений підспівувачами до абсурду, що призвело до фізичного знищення нещасного оператора в ряді мов. Інквізиція палила старі книги, співала дифірамби кастрата, а в школах заборонили навіть згадка обрізаного рудимента (який став атавізмом).

В попередній статті ми запропонували такий синтаксис, який не залишає місця оператору «goto». З якого боку не глянь на гіпотетичні ділянки коду програми - всюди запропоновані конструкції, які і лаконічніше, і зрозуміліше, ніж еквівалентні варіанти з «goto». Цикли, умовний оператор, перемикач не потребують «goto». Як бачимо, причина «вбивства goto" не релігійна, а чисто практична: він абсолютно не потрібен.
Залишається останній аргумент: текст програми може створюватися не людиною, а іншою програмою; в цьому випадку він би став у нагоді.
Але на це теж є заперечення:
  • По-перше, далеко не факт, що розробляється нами мову буде досточно хороший як мову низького рівня, свого роду асемблер. Мова Сі для цих цілей, напевно, більш походящ. Компілятор Сі є фактично для всіх платформ.
  • По-друге, розроблені нами конструкції дозволяють обійтися без «goto» не тільки програмісту, але програмі, яка генерує код.
  • Ну і по-третє, включити його в мову ніколи не пізно, завжди встигну. А ось виключити його буде набагато складніше.

Не вірте данайців, «goto» приносить

Прихильники «goto» можуть виправдовувати право на існування цього оператора складності поставленого завдання. Наприклад, в статті « Заборонений плід GOTO солодкий! »Наводиться досить складна, на перший погляд, блок-схема: Автор зазначеної статті призводить реалізація алгоритму цієї блок схеми з використанням« goto », яка виглядає так: if (a) {A; goto L3; } L1: if (b) {L2: B; L3: C; goto L1; } Else if (! C) {D; goto L2; } E; Без «goto» вона значно довше: char bf1, bf2, bf3; if (a) {A; bf1 = 1; } Else bf1 = 0; bf2 = 0; do {do {if (bf3 || b) bf3 = 1; else bf3 = 0; if (bf3 || bf2) B; if (bf3 || bf1 || bf2) {C; bf1 = 0; bf2 = 1; } If (! Bf3) {if (! C) {D; bf3 = 1; } Else {bf3 = 0; bf2 = 0; }}} While (bf3); } While (bf2); E; З цього начебто треба зробити висновок, що «goto» в якихось випадках допомагає написати код коротше і зрозуміліше. Не будемо поспішати робити такі висновки. Справа в тому, що наведена блок-схема демонструє «творчий безлад» в голові її автора. Так блок-схеми писатися не повинні. Переробимо її, десь сподіваючись на інтуїцію, а де скористаємося порадами Володимира Даніелович Паронджанова - найвідомішого спеціаліста в країні по блок-схемам. Він радить розташовувати вихід з блок-схеми строго під входом. Зробимо перестановки блоків у схемі, нічого не змінюючи - просто маємо блоки по-іншому. Отримана блок-схема повністю еквівалентна вихідної. Тепер розглянемо блок-схему уважніше.
Коли умова «a» істинно, маршрут виконання програми передбачає послідовне виконання блоків «A» і «C», а після чого маршрут призводить до умови «b». Коли «a» помилково, до умови «b» потрапляють відразу.
Коли умова «b» істинно, маршрут виконання програми передбачає послідовне виконання блоків «B» і «C», а після чого маршрут знову призводить до умови «b». Коли «b» помилково, потрапляють до умови «c».
Коли умова «c» помилково, маршрут виконання програми передбачає послідовне виконання блоків «D», «B» і «C», а після чого маршрут знову призводить до умови «b». Коли «c» істинно, виконується блок «E» і на цьому алгоритм завершується.
Тепер знову озброюємось вченням В.Паронджанова, автора «Дракона». «Дракон» - це свого роду нормалізовані блок-схеми, що гарантують неперетинання ліній блок-схем. Знову перетворимо блок-схему, та так, щоб лінії не перетиналися: Блок схема стала вельми і вельми простий. Цьому алгоритму відповідає такий код на Сі: if (a) {A; C;} do {if (b) {B; C; continue;} D; B; C; } While (! C); E; Порівнюючи цей код з тим, що запропонував автор статті на «Хабрахабр», можна вигукнути: «Не вірте данайців,« goto »приносить».
Ті перетворення блок-схеми, які зроблені, щоб прийти до такого короткого рішенням, робилися більше з натхнення. Якщо ж Вам була дана складна блок-схема, яку належить втілити в код, то краще перетворювати її «по науці». Існує строгий математичний доказ, що будь-яка блок-схема може бути перетворена в еквівалентну, яка виключає перетин маршрутних ліній. Це дуже важливий науковий висновок. Неперетинання маршрутних ліній блок-схеми рівнозначно тому, що в програмі не буде операторів «goto».
Висновок: які б докази не приводили на захист «goto», завжди знайдеться спосіб обійтися без нього і написати програму коротше і не менш наочно. При наявності зручних конструкцій в мові, звичайно.

Що ще почитати на цю тему

Опубліковано: 2012.09.25, остання правка: 2019.01.27 20:17


Відгуки

2013/05/15 19:11, Vovanium #

Взагалі кажучи, вихід з глибоко вкладеного циклу за межі зовнішнього циклу є єдиним виправданням любителів «goto».

Не дуже то досвідчені любителі траплялися, видно. Претендентом на «goto» є будь-яка структура управління, що не розкладається на елементарні розгалуження і цикли без повторів.
Мені ось періодично трапляється такого роду:
"Якщо a то (A, якщо b то B інакше C) інакше C"
Де A, B, C - деякі послідовності дій, можливо досить довгі, можливо використовують загальні змінні і т. П.
Тут C має виконуватися, якщо не виповнилося умова a АБО вкладене умова b. Послідовність A не дає використовувати "якщо a або b то ... інакше C".
Кожен раз встає дилема:
або писати код з повтором;
або використовувати третя умова
або факторізовать ділянку C в процедуру,
або використовувати «goto».
Часом виявляється, що «goto» виграє у кожного з варіантів за розміром коду, швидкості, читабельності, а то і по всіх параметрах відразу.
Подібний же приклад - безліч альтернативних гілок (if або switch / case не важливо), і кожна гілка може завершитися умовно успішно, або неуспішно, і в залежності від цього треба завершити процедуру тим чи іншим методом.
На цей випадок у багатьох мовах є механізм винятків, який по суті - той же завуальований «goto», та ще й набагато менш передбачуваний, приблизно як longjmp.

2013/05/16 15:28 Автор сайту #

А як цей код виграє від «goto»? (Якщо а
А (...)
(Якщо b
В (...)
інакше
C (...))
інакше
C (...)) Що поганого в тому, щоб зробити C (...) процедурою? Два повторюваних ділянки коду краще замінити процедурою; виправлення, що вносяться до С (...), будуть діяти в двох місцях. Інакше доведеться в два ділянки вносити однакові виправлення. При неуважності виправлення можуть зробити код неідентичною.

2014/01/16 9:56, Pensulo #

На VisualBasic лаконічніше буде вирішити задачку таким чином: If a Then
A ()
ElseIf b Then
B ()
Else
C ()
End If Де a, b, c - логічні вираження
A (), B (), C () - виконуються операції (окремим випадком яких є виклик функцій)

2014/04/29 2:36, Utkin #

Що поганого в тому, щоб зробити C (...) процедурою?

Те, що С може використовувати поточний контекст, тобто місцеві локальні змінні, які доведеться передавати потім в процедуру і повертати їх якось кілька штук. Як пам'ятається, найбільш стале уявлення про функції передбачає завжди один, єдиний результат.

2014/04/30 12:49, Автор сайту #

Якщо ділянки ідентичні, то вони контекст використовують однаково. Зв'язування процедури із зовнішнім оточенням через параметри - це, звичайно, накладні витрати. Правда, в C ++ є inline-процедури: в місці виклику буде робитися не виклик процедури, а підстановка її коду. В цьому випадку накладні витрати виключені. Результат же можна не повертати, а змінювати через покажчик, переданий як параметр, наприклад: strcpy (char * куди, const char * звідки); // копіювання рядків

2014/06/17 4:36, utkin #

Результат же можна не повертати, а змінювати через покажчик, переданий як параметр, наприклад:

Сучасна тенденція - відмова від покажчиків і це правильно. Покажчики важко відстежувати і повільно і складно. Загалом неефективно. А програмісту довіряти покажчики не можна - він погано уявляє механізми роботи всієї системи. Це призводить до витоку пам'яті, зависань, уязвимостям в безпеці системи. Загалом явно так зазвичай не говорять, але зараз покажчики це зло. Є більш вискоуровневие механізми - динамічні масиви і списки.

В цьому випадку накладні витрати виключені.

Ці витрати вилазять в налагодженні програми у вигляді значних неконтрольованих тимчасових витрат.

2014/06/17 16:35, Автор сайту #

Йшлося про те, як обійтися без «goto». Його застосовують в тому випадку, коли виконавець погано уявляє, як зробити хороший алгоритм. В цьому випадку можна дати милиці, менш стрьомні, ніж «goto». Хоча, по-хорошому, треба заново обміркувати алгоритм.

Є більш вискоуровневие механізми - динамічні масиви і списки.

Є рішення ще краще - використання чистих функцій, наприклад. Все інше - від лукавого. Динамічні масиви - про них теж поки голосно не говорять, що це є зло. Але скоро скажуть.

2014/06/30 12:19, utkin #

Його застосовують в тому випадку, коли виконавець погано уявляє, як зробити хороший алгоритм.

А що значить «хороший» алгоритм? Чим вимірюється хорошість «goto»? Не забувайте, що в асемблері ціле сімейство «goto», і програми написані і працюють. Зрештою, компілятор також переводить програму без «goto» в програму з численними варіаціями умовних переходів, а часто і з безумовними переходами.

Динамічні масиви - про них теж поки голосно не говорять, що це є зло.

У плані використання пам'яті так, але краще ніж покажчики - тому що відслідковуються і легко знищуються. Об'єкти, створені за посиланнями, можуть бути втрачені, можливі помилки обчислення покажчиків і т.д. Динамічні масиви більш «порядочнее» в тому плані, що все видно і легко «змити» за собою в кінці роботи.

2014/06/30 16:15, Автор сайту #

А що значить «хороший» алгоритм?

Очевидний, прозорий, чи не вводить в оману.

Зрештою компілятор також переводить безготовую програму в програму з численними варіаціями умовних переходів, а часто і з безумовними переходами.

Ну так ці компілятори ще й в двійковий код все перетворять. Але це не привід писати в довічних кодах: прогрес не стояв на місці.

Об'єкти, створені за посиланнями, можуть бути втрачені, можливі помилки обчислення покажчиків і т.д. Динамічні масиви більш «порядочнее» в тому плані, що все видно і легко «змити» за собою в кінці роботи.

Будь-який об'єкт, створений в динамічної пам'яті (в тому числі і динамічні масиви), доступний тільки через його адресу, який в C ++ має матеріальне втілення у вигляді покажчика або посилання. В інших мовах це просто заховано за куліси і створюється враження «порядності».
Я на тему пам'яті напишу через деякий час.

2014/06/30 17:43, utkin #

Очевидний, прозорий, чи не вводить в оману.

Це дуже хитка тема. Навіть перегукуючись з сусідніми темами - для мене а ++ не очевидно, непрозоро і вводить в оману (в поєднаннях а ++, ++ а, а = а + 1). Однак більшість мов програмування використовують таку (або аналогічну) запис. Якщо ж просто докопуватися - маячня і сложночітаемую програму можна написати і структуровано (використовуючи неочевидні реалізації алгоритму). У той же час можна використовувати «goto» з розумом, організувавши переходи строго логічно, якщо виробити методику і прикласти деякі зусилля. Єдиний постулат, що знищує «goto», це тільки те, що будь-яку програму можна написати без використання «goto». Більше об'єктивних причин для вигнання цього оператора немає.

В інших мовах це просто заховано за куліси і створюється враження «порядності».

У моєму улюбленому Паскалі зручна реалізація динамічних масивів, що виключає ситуації коли посилання на об'єкт в масиві забута, втрачена, обчислена за межі масиву. Також як і безумовні переходи асемблера - мені немає особливої ​​справи до того як реалізовані масиви, важливо що їх використання однозначно зменшує кількість помилок ведуть до падіння програм.

2015/10/25 5:35, rst256 #

Здається замість «goto» нам пропонують копіпаст шматки коду, в такому випадку я теж відповім копіпастом.
Стр.457. Моя позиція по відношенню до концепції структурного програмування не поміщається в Вашу класифікацію. Можливо, хтось ще дотримується подібної точки зору, але я таких не знаю. Я вважаю цю концепцію помилковою і шкідливою. Оператор «goto» абсолютно нешкідливий оператор в порівнянні з циклом типу «while» і покажчиками, які представляють серйозну біду для програмування. Позитивним було лише постановка задачі побудови хороших програм і поштовх до досліджень в цьому напрямку. Структурне програмування було впроваджено як релігія і до сих працює як релігія. Невдала спроба усунення оператора «goto» з мов програмування, вакханалія структурного програмування довгі роки - це процес в хибному напрямку.
Джерело: http://drakon.su/_media/kritika/kritika_01.rec.pdf

2015/10/25 18:31, Автор сайту #

Я задавав питання Андрію Карпову, як впливає «goto» на роботу аналізатора коду PVS-Studio. Він відповів: «Дуже погано». Обіцяв статтю на цю тему, але поки її немає. Тобто негативну думку про це операторі належить не теоретику програмування, а практику. Та й навіщо в шматок коду, який повинен виконуватися багаторазово, переходити по «goto»? Цей код треба зробити inline-функцією. Компілятор зробить або підстановку при оптимізації на швидкість або виклик при оптимізації на розмір.
«Дикі» покажчики - дійсно погана практика. І звичайних циклів краще уникати, замінюючи їх, де виходить, циклом «for each». Але це не означає, що «goto» - це краще, ніж покажчики і цикли. У безлічі цілком вдалих мов «goto» відсутній, і я не зустрічав скарг розробників, що їм його не вистачає.

2015/11/13 1:46, rst256 #

Я задавав питання Андрію Карпову, як впливає «goto» на роботу аналізатора коду PVS-Studio. Він відповів: «Дуже погано».

Тобто в питанні вибору стилю кодування ми вибираємо варіант найбільш зручний аналізатору коду, тому що йому складно розібратися в переходах? Програмісту не складно, компілятору теж, але аналізатор важливіше адже в коді без «goto» починає плутатися програміст, адже то що робилося простий логічною командою тепер потрібно робити через допоплнітеьние змінні, повторні перевірки, дублювання коду і т.д. А «goto» компілятор все одно в код додасть в результаті ...

2015/11/13 17:01, Автор сайту #

Все, що можна зробити, застосовуючи «goto», можна зробити і без нього, не використовуючи додаткові змінні, що не дублюючи код. Поява ж інструкцій «jmp» в виконуваному коді неминуче. Але це вже не важливо, тому що він з'явиться поле компіляції програми, правильно написаної завдяки відсутності «goto».

2016/03/25 4:58, rst256 #

такий код на Сі: while (1) {...

А це нормальний аналізатор не збентежить? Або він такий розумний став що визначає таке. Тоді які проблеми у нього з «goto»?
У будь-якому випадку таки да тоді нам вистачить покаона (while (1) => while alone) але щоб окремої конструкцією pokaone {...}

2016/04/04 13:33, Автор сайту #

Цикл має вихід за умовою. Схоже на for (;! C;), тільки перевірка не на початку, а в середині.

2016/04/11 16:54, rst256 #

Ні, не тільки вихід за умовою, але і продовження.
while 1 {
...
if some_condition_break1 then ... break end
...
if some_condition_break1 then ... break end
...
if some_condition_continue1 then ... continue end
...
}
причому "then ..." це ще й певний набір дій перед виходом / продовженням циклу.
А взагалі не чіпайте краще «goto», поганий програміст без нього просто замість спагеті створить матрьошку, що нічим не краще.
А код хорошого програміста із застосуванням «goto» буде завжди легко читати, а й застосує він його лише там де структурний підхід лише ускладнить код.

2016/04/11 18:03, Автор сайту #

Код, який потрібно виконати при виході, можна оформити звичайними конструкціями: (if умова
код при виході
break)
Те ж саме - для «continue». Якщо виходів кілька, то було б бажано код не дублювати. Припустимо, це можна зробити так: (while умова
(If умова 1
break)
(If умова 2
break)
on break
код при виході) Але це обтяжить мову. Ви, гадаю, хочете вирішити всі проблеми простим наявністю «goto»? «Goto» полегшує мову?

2016/07/13 9:14, rst256 #

«Goto» полегшує мову?

Безсумнівно, всі прийоми структурного програмування можна уявити через «goto»: він універсальний оператор, а структурний підхід - це обмежений набір з декількох конструкцій. Це можна порівняти з ливарної формою і різцем, форма виграє проти різця, але тільки поки вона збігається з тим, що вам потрібно отримати ...
Так ви точно впевнені, що різець вам таки ніколи не знадобиться, і набору з десятка форм вистачить на всі випадки життя?

2016/07/13 9:19, rst256 #

Просто додамо ще коду ... (while умова
(If умова 1
break 2)
(If умова 2
break1)
(If умова 3
...
(If умова 4
break 1)
...
)
on break1
код при виході 1
on break 2
код при виході 2
) І структурне програмування вже не тягне ...

2016/07/13 09:39 rst256 #

Висновок: які б докази не приводили на захист «goto», завжди знайдеться спосіб обійтися без нього і написати програму коротше і не менш наочно. При наявності зручних конструкцій в мові, звичайно.

Например #define, так? А що тоді заважає підставіті туди «goto»? Так хоч багів менше буде, например в одному з блоків присутній "int i;" буде баг, а як рекурсию такий підхід подужає? Рекурсію через «goto» іноді оптімальніше делать.
Системний мову, орієнтований на швидкодію, повинен мати оператор «goto»!

2016/07/13 18:39, Автор сайту #

«Goto»: він універсальний оператор, а структурний підхід - це обмежений набір з декількох конструкцій ... Так ви точно впевнені що різець вам таки ніколи не знадобиться, і набору з десятка форм вистачить на всі випадки життя?

«Goto» не виконує операції над даними. Цей оператор лише керує ходом обчислень. Які алгоритми потребують саме в «goto»? Можна навести приклад складнощів, які виникнуть при реалізації алгоритму, якщо «goto» відсутній? З алгоритмічної складністю можна справлятися або декомпозицією, або інструментами типу «Дракона» (свого роду «нормалізація» блок-схем). Обмеженість набору кубиків, з яких складається алгоритм, не є проблемою, якщо забезпечується достатність. А якщо це сприяє верифікації алгоритму інструментами типу PVS-Studio, то таку обмеженість можна навіть вітати.
Такий код краще: (while умова А
(If умова 1
break)
(While умова Б
(If умова 2
break 2)
(If умова 3
break)
...
on break
код при виході з внутрішнього циклу
)
on break
код при виході з осяжний циклу
) Тоді все виглядає логічніше.

Системний мову, орієнтований на швидкодію, повинен мати оператор «goto»!

Мова системного програмування повинен мати повний набір операцій для роботи з даними. Для інших мов це не обов'язково. А ось якихось особливих алгоритмів в системному програмуванні немає. Всі алгоритми можуть бути представлені у вигляді нормалізованих блок-схем, які гарантують неперетинання гілок алгоритму:

В. Існує строгий математичний доказ, що будь-яка блок-схема може бути перетворена в еквівалентну, яка виключає перетин маршрутних ліній. Це дуже важливий науковий висновок. Неперетинання маршрутних ліній блок-схеми рівнозначно тому, що в програмі не буде операторів «goto».

2016/09/08 7:46, rst256 #

Можна навести приклад складнощів, які виникнуть при реалізації алгоритму, якщо «goto» відсутній?

Складнощів або алгоритму? Якщо складнощів, то вона завжди одна: «goto» відсутня! Якщо алгоритмів, то це в основному метапрограмірованіе: цикл з умовою в середині, генерація коду самим Драконом. Знай ми свідомо необхідний алгоритм, змогли б напевно переписати його без «goto», але от лихо: ми його в даному випадку НЕ ЗНАЄМО, той же цикл з умовою в середині: ... код ...
нач_цікла1:
... код ...
(Якщо умова goto кон_цікла1)
... код ...
goto нач_цікла1;
кон_цікла1:
... код ... Звичайно якщо ви віддаєте перевагу хак "while (1) ..." можна і його використовувати, але як ви тоді реалізуєте наприклад break 2? І ще такий момент: може бути В. Паронджанов навпаки дуже сильно любить «goto», і не бажає їм ні з ким ділитися? Адже додай він його в свою мову - йому довелося б враховувати можливість конфлікту міток користувача і генерує сам Драконом.

2019/02/08 10:23 kt #

Хотілося б згадати і про «кошерної» GOTO.
Я маю на увазі переходи в програмах на асемблері. Свого часу, по-моєму, в асемблері СМ-4 я побачив таку примочку, як «тимчасові» або «одноразові» мітки. Тобто там можна було використовувати мітки з іменами $ 1 $ 63 в тексті між двома «справжніми» тобто звичайними мітками. Після чергової звичайної мітки знову можна було використовувати мітки, що починаються з $, і тепер це були вже інші місця в тексті.
Оскільки я тоді багато писав на асемблері, і мені набридало вигадувати унікальні назви, я вставив схожий механізм в транслятор RASM. Мітки можна було просто позначати символом @. У транслятора був внутрішній лічильник цих міток. Кожен раз, коли в операндах команди зустрічався @, транслятор додавав до нього 16-ковий значення цього лічильника у вигляді тексту, тобто виходили мітки @ 0000 @ 0001 і так до @FFFF. Коли ж транслятор зустрічав саму чергову мітку (тобто текст @ :), він теж прісобачівал до неї номер і потім збільшував лічильник на 1.
До чого все це я? В результаті на асемблері виходили трохи більше кошерні переходи, оскільки на такі мітки можна було переходити тільки вперед. І якщо дотримуватися правил, що до найближчої мітки @ в тексті інших позначок не повинно бути, асемблерний текст з переходами читався набагато легше. Читаєш і розумієш, що перехід йде вниз по тексту і зазвичай кудись недалеко, тобто ось зараз ця мітка і з'явиться.
Мені здається, що якщо в мові високого рівня мати подібний механізм «одноразових» міток, кошерность GOTO підвищиться. Хоча, звичайно, і помилки легко вносити.

2019/02/08 16:34, Автор сайту #

Ідея, звичайно, оригінальна і дотепна. Я б, напевно, цим із задоволенням користувався. Якщо, звичайно, повернути ті часи, коли трава була зеленішою, а ночами снилися програми на асемблері. Але мови високого рівня без цього обійдуться, так буде краще і програмами, і програмістам. Арсенал різних видів розгалужень в мовах високого рівня не дає шансів «goto» і суворіше дотримується структуру програми.

Додати свой відгук

Написати автору можна на електронну пошту mail (аt) compiler.su

А що значить «хороший» алгоритм?
Чим вимірюється хорошість «goto»?
Та й навіщо в шматок коду, який повинен виконуватися багаторазово, переходити по «goto»?
Тобто в питанні вибору стилю кодування ми вибираємо варіант найбільш зручний аналізатору коду, тому що йому складно розібратися в переходах?
А це нормальний аналізатор не збентежить?
Тоді які проблеми у нього з «goto»?
Ви, гадаю, хочете вирішити всі проблеми простим наявністю «goto»?
«Goto» полегшує мову?
Так ви точно впевнені, що різець вам таки ніколи не знадобиться, і набору з десятка форм вистачить на всі випадки життя?
Например #define, так?
Провайдеры:
  • 08.09.2015

    Batyevka.NET предоставляет услуги доступа к сети Интернет на территории Соломенского района г. Киева.Наша миссия —... 
    Читать полностью

  • 08.09.2015
    IPNET

    Компания IPNET — это крупнейший оператор и технологический лидер на рынке телекоммуникаций Киева. Мы предоставляем... 
    Читать полностью

  • 08.09.2015
    Boryspil.Net

    Интернет-провайдер «Boryspil.net» начал свою работу в 2008 году и на данный момент является одним из крупнейших поставщиков... 
    Читать полностью

  • 08.09.2015
    4OKNET

    Наша компания работает в сфере телекоммуникационных услуг, а именно — предоставлении доступа в сеть интернет.Уже... 
    Читать полностью

  • 08.09.2015
    Телегруп

    ДП «Телегруп-Украина» – IT-компания с 15-летним опытом работы на рынке телекоммуникационных услуг, а также официальный... 
    Читать полностью

  • 08.09.2015
    Софтлинк

    Высокая скоростьМы являемся участником Украинского центра обмена трафиком (UA — IX) с включением 10 Гбит / сек... 
    Читать полностью