Шаги для создания примера. Программное создание Connection

Шаги для создания примера. Программное создание Connection

04.04.2019

Достойна ли архитектура Haswell называться новой и переработанной?

Более пяти лет Intel придерживается стратегии «тик-так», чередуя перевод конкретной архитектуры на более тонкие технологические нормы с выпуском новой архитектуры.

В итоге каждый год мы получаем либо новую архитектуру, либо переход на новый техпроцесс. На 2013 год был запланирован «так», то есть выпуск новой архитектуры - Haswell. Процессоры с новой архитектурой выпускаются по тому же техпроцессу, что и предыдущее поколение Ivy Bridge : 22 нм, Tri-gate. Техпроцесс не поменялся, при этом количество транзисторов увеличилось, а значит, и конечная площадь кристалла нового процессора тоже увеличилась - а вслед за ней и энергопотребление.

Придерживаясь традиций, Intel в день анонса Haswell представила только производительные и дорогие процессоры линеек Core i5 и i7. Анонс двухъядерных процессоров младших линеек как всегда идет с задержкой. Стоит заметить, что цены на новые процессоры остались на том же уровне, что и у Ivy Bridge.

Сравним площади кристаллов разных поколений четырехъядерных процессоров:

Как видим, четырехъядерный Haswell имеет площадь всего 177 мм², при этом в него интегрирован северный мост, контроллер оперативной памяти и графическое ядро. Таким образом, количество транзисторов увеличилось на 200 миллионов, а площадь подросла на 17 мм². Если же сравнить Haswell с 32-нанометровыми Sandy Bridge, то количество транзисторов увеличилось на 440 миллионов (38%), а площадь за счет перехода на техпроцесс 22 нм сократилась на 39 мм² (18%). Тепловыделение все эти годы держалось практически на одном уровне (95 Вт у SB и 84 Вт у Haswell), а площадь уменьшалась.

Всё это привело к тому, что с каждого квадратного миллиметра кристалла приходится отводить больше тепла. Если раньше с 216 мм² надо было забирать 95 Вт, то есть 0,44 Вт/мм², то теперь с площади в 177 мм² надо забирать 84 Вт - 0,47 Вт/мм², что на 6,8% больше, чем раньше. Если эта тенденция сохранится, то скоро будет просто физически сложно отводить тепло с таких маленьких площадей.

Рассуждая чисто теоретически, можно предположить, что если в Broadwell, который будет производиться по техпроцессу 14 нм, количество транзисторов возрастет на 21%, как при переходе с 32 на 22 нм, а площадь при этом сократится на 26% (на ту же величину, что и при переходе с 32 на 22 нм), то мы получим 1.9 млрд. транзисторов на площади 131 мм². Если при этом тепловыделение также упадет на 19%, то у нас получится 68 Вт, или 0,52 Вт/мм².

Это теоретические расчеты, на практике будет иначе - переход техпроцесса с 32 на 22 нм также был ознаменован введением 3D-транзисторов, которые снизили токи утечки, а с ними и тепловыделение. Однако про переход с 22 нм на 14 нм пока ничего такого не слышно, так что на практике значения тепловыделения скорее всего будут еще хуже, и на 0,52 Вт/мм² надеяться не стоит. Тем не менее, даже если уровень тепловыделения будет 0,52 Вт/мм², проблема локального перегрева и сложность отвода тепла с маленького кристалла обострятся еще больше.

Кстати, именно сложности с отводом тепла при тепловыделении на уровне 0,52 Вт/мм² могут лежать в основе желания Intel перейти на BGA или попыток упразднить сокет. Если процессор будет распаян на материнской плате, то тепло будет непосредственно передаваться от кристалла к радиатору без промежуточной крышки. Это выглядит еще более актуальным в свете замены припоя на термопасту под крышками современных процессоров. Можно снова ожидать появления «голых» процессоров с открытыми кристаллами по примеру Athlon XP, т. е. без крышки как промежуточного звена в теполоотводе.

На видеокартах давно уже делается именно так, а опасность сколоть кристалл нивелируется железной рамкой вокруг него, поэтому у видеокарт нет таких «актуальных проблем», как термопаста под крышкой процессора. Тем не менее, разгон станет еще более сложным занятием, а правильное охлаждение «более тонких» процессоров - чуть ли не наукой. И всё это нас ожидает совсем скоро, если, конечно, не произойдет чудо…

Но опустимся на землю и вернемся к разговору о Haswell. Как мы знаем, Haswell получил ряд «улучшений/изменений» относительно Sandy Bridge (и, соответственно, Ivy Bridge, являвшегося, по большому счету, переводом SB на более тонкий техпроцесс):

  • встроенный регулятор напряжения;
  • новые энергосберегающие режимы;
  • увеличение объемов буферов и очередей;
  • увеличение пропускных способностей кэшей;
  • увеличение количества портов запуска;
  • добавление новых блоков, функций, API в интегрированном графическом ядре;
  • увеличение количества конвейеров в графическом ядре.

Таким образом, обзор новой платформы можно разделить на три части: процессор, встроенный графический ускоритель, чипсет.

Процессорная часть

Изменения в процессоре включают добавление новых инструкций и новых режимов энергосбережения, встраивание регулятора напряжения, а также изменения в самом процессорном ядре.

Наборы инструкций

В архитектуре Haswell появились новые наборы инструкций. Их можно условно разделить на две большие группы: направленные на увеличение векторной производительности и направленные на серверный сегмент. К первым относятся AVX и FMA3, ко вторым - виртуализация и транзакционная память.

Advanced Vector Extensions 2 (AVX2)

Набор AVX был расширен до версии AVX 2.0. Набор AVX2 предоставляет:

  • поддержку 256-битных целочисленных векторов (ранее была поддержка только 128-битных);
  • поддержку gather-инструкций, которые снимают требование непрерывного расположения данных в памяти; теперь данные «собираются» с разных адресов памяти - интересно будет посмотреть, как это повлияет на производительность;
  • добавление инструкций манипуляций/операций над битами.

В целом, новый набор больше ориентирован на целочисленную арифметику, и основной выигрыш от AVX 2.0 будет виден лишь в целочисленных операциях.

Fused Multiply-Add (FMA3)

FMA - это операции совмещенного умножения-сложения, при которых умножаются два числа и складываются с аккумулятором. Данный тип операций достаточно распространен и позволяет более эффективно реализовывать умножение векторов и матриц. Поддержка данного расширения должна значительно увеличить производительность векторных операций. FMA3 уже поддерживается в процессорах AMD с ядром Piledriver, а FMA4 - в Bulldozer.

FMA представляет собой комбинацию операции умножения и сложения: a=b×c+d.

Что касается FMA3, то это трехоперандные инструкции, то есть запись результата производится в один из трех участвующих в инструкции операндов. В итоге мы получаем операцию типа a=b×c+a, a=a×b+c, a=b×a+c.

FMA4 - это четырехоперандные инструкции с записью результата в четвертый операнд. Инструкция приобретает вид: a=b×c+d.

К слову об FMA3: данное нововведение позволит увеличить производительность более чем на 30% при условии адаптации кода под FMA3. Стоит заметить, что когда Haswell еще был далеко на горизонте, Intel планировала внедрять FMA4, а не FMA3, но впоследствии изменила решение в пользу FMA3. Скорее всего, именно из-за этого Bulldozer вышел с поддержкой FMA4: дескать, не успели переделать под Intel (а вот Piledriver вышел уже с FMA3). Причем изначально Bulldozer в 2007 году планировался именно с FMA3, но после обнародования планов Intel внедрить FMA4 в 2008 году AMD свое решение переиграла, выпустив Bulldozer с FMA4. А Intel затем сменила в планах FMA4 на FMA3, поскольку выигрыш от FMA4 по сравнению с FMA3 небольшой, а усложнение электрических логических схем - значительное, что также увеличивает транзисторный бюджет.

Выигрыш от AVX2 и FMA3 проявится после адаптации ПО под эти наборы инструкций, так что роста производительности «здесь и сейчас» ждать не стоит. А поскольку производители ПО достаточно инертны, то с «дополнительной» производительностью придется подождать.

Транзакционная память

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

В Haswell появилось новое расширение Transactional Synchronization Extensions (TSX) - транзакционная память, которая предназначена для эффективной реализации многопоточных программ и повышения их надежности. Данное расширение позволяет реализовать «в железе» транзакционную память, тем самым повысив общую производительность.

Что такое транзакционная память? Это такая память, которая имеет внутри себя механизм управления параллельными процессами для обеспечения доступа к совместно используемым данным. Расширение TSX состоит из двух компонентов: Hardware Lock Elision (HLE) и Restricted Transaction Memory (RTM).

Компонент RTM представляет собой набор инструкций, с помощью которого программист может начать, закончить и прервать транзакцию. Компонент HLE вводит префиксы, которые игнорируются процессорами без поддержки TSX. Префиксы обеспечивают блокировку переменных, позволяя другим процессам использовать (считывать) заблокированные переменные и исполнять свой код до тех пор, пока не произойдет конфликт записи заблокированных данных.

На данный момент уже появились приложения с использованием данного расширения.

Виртуализация

Важность виртуализации постоянно растет: все чаще множество виртуальных серверов расположены на одном физическом, да и облачные сервисы распространяются все шире. Поэтому увеличение скорости работы технологий виртуализации и виртуализированных сред является очень актуальной задачей в серверном сегменте. В Haswell содержатся некоторые улучшения, направленные именно на увеличение производительности виртуализированных сред. Перечислим их:

  • улучшения, позволяющие сократить время перехода из гостевых систем в host-систему;
  • добавились биты доступа в Extended Page Table (EPT);
  • уменьшилось время доступа к TLB;
  • новые инструкции вызова гипервизора без выполнения команды vmexit;

В итоге время перехода между виртуализированными средами сократилось и составляет менее 500 тактов процессора. Это должно приводить к сокращению общих потерь производительности, связанных с виртуализацией. А новые Xeon E3-12xx-v3 предположительно будут быстрее в этом классе задач, чем Xeon E3-12xx-v2.

Встроенный регулятор напряжения

В Haswell регулятор напряжения переехал с материнской платы под крышку процессора. Ранее (Sandy Bridge) к процессору требовалось подводить различные напряжения для графического ядра, для системного агента, для процессорных ядер и др. Теперь к процессору через сокет подводится только одно напряжение Vccin 1,75 В, которое поступает на встроенный регулятор напряжения. Регулятор напряжения представляет собой 20 ячеек, каждая ячейка создает 16 фаз с общей силой тока в 25 А. В сумме мы получаем 320 фаз, что значительно больше, чем даже у самых навороченных материнских плат. Такой подход позволяет не только упростить разводку материнских плат (а значит, и снизить их стоимость), но и более точно регулировать напряжения внутри процессора, что, в свою очередь, ведет к большей экономии электроэнергии.

Это одна из основных причин, по которым Haswell физически не может быть совместимым со старым сокетом LGA1155. Да, можно говорить о желании Intel зарабатывать деньги, каждый год выпуская новую платформу (новый чипсет) и каждые два года - новый сокет, но в данном случае для смены сокета есть объективные причины: физическая/электрическая несовместимость.

Однако за все приходится платить. Регулятор напряжения - еще один заметный источник тепла в новом процессоре. А учитывая, что Haswell производится по нормам того же техпроцесса, что и его предшественник Ivy Bridge, стоит ожидать, что процессор будет горячее.

Вообще, это улучшение больше пользы принесет в мобильном сегменте: более быстрое и точное изменение напряжения позволит снизить энергопотребление, а также более эффективно управлять частотой процессорных ядер. И судя по всему, это не пустое маркетинговое заявление, потому как Intel собирается анонсировать мобильные процессоры со сверхнизким потреблением энергии.

Новые энергосберегающие режимы

В Haswell появились новые состояния сна S0ix, которые похожи на состояния S3/S4, но только с гораздо меньшим временем перехода процессора в рабочее состояние. Также было добавлено новое состояние простоя С7.

Режим С7 сопровождается выключением основной части процессора, при этом изображение на экране остается активным.

Минимальная частота процессоров в простое составляет 800 МГц, это также должно снизить энергопотребление.

Архитектура процессора

Фронт-энд

Конвейер Haswell, как и в SB, имеет 14–19 стадий: 14 стадий при попадании в µop-кэш, 19 - при промахе. Объем µop-кэша не изменился по сравнению с SB - 1536 µop. Организация кэша мопов осталась такой же, как и в SB - 32 набора по восемь строк, в каждой из которых по шесть мопов. Хотя в связи с увеличением количества исполнительных устройств, а также последующих после кэша мопов буферов можно было бы ожидать увеличения кэша мопов - до 1776 мопов (почему именно такой объем - будет сказано ниже).

Декодер

Декодер, можно сказать, не изменился - остался четырехпутным, как у SB. Он состоит из четырех параллельных каналов: одного сложного транслятора (complex decoder) и трех простых (simple decoder). Сложный транслятор может обрабатывать/декодировать сложные инструкции, порождающие более одного мопа. В трех остальных каналах декодируются простые инструкции. К слову, благодаря наличию слияния макроопераций, инструкции загрузки с исполнением и выгрузки порождают, например, один моп и могут быть декодированы в «простых» каналах декодера. Инструкции SSE тоже порождают один моп, поэтому могут быть декодированы в любом из трех простых каналов. Учитывая появление 256-битных AVX, FMA3, а также увеличенное количество портов запуска и функциональных устройств, такой скорости декодера может попросту не хватить - и он может стать узким местом. Частично данное узкое место «расшивает» кэш мопов L0m, но все равно, имея процессор с 8 портами запуска, Intel следует задуматься о расширении декодера - в частности, не помешало бы увеличить количество сложных каналов.

Планировщик, буфер переупорядочивания, исполнительные устройства

После декодера следует очередь декодированных инструкций, и вот тут мы видим первое изменение. В SB было две очереди по 28 записей - одна очередь на один виртуальный поток Hyper-Threading (НТ). В Haswell две очереди объединили в одну общую для двух потоков HT на 56 записей, то есть объем очереди не изменился, но изменилась концепция. Теперь весь объем в 56 записей доступен одному потоку при отсутствии второго - следовательно, можно ожидать прироста как в малопоточных приложениях, так и в многопоточных (это связано с тем, что единую очередь два потока могут использовать более эффективно).

Изменению подвергся также буфер переупорядочивания - он был увеличен со 168 до 192 записей. Это должно повысить эффективность HT за счет большей вероятности наличия «независимых» друг от друга мопов. Очередь декодированных микроопераций увеличена с 54 до 60. Физические регистровые файлы, которые появились в SB, также были увеличены - со 160 до 168 регистров для целочисленных операндов и со 144 до 168 для операндов с плавающей запятой, что должно положительно сказаться на производительности векторных вычислений.

Сведем все данные об изменениях в буферах и очередях в единую таблицу.

В принципе, изменения параметров в Haswell выглядят вполне ожидаемыми, учитывая общую логику развития процессорной архитектуры Intel. Исходя из этой же логики, можно предположить, что в следующем поколении Core размеры буферов и очередей увеличатся не более чем на 14%, то есть размер буфера переупорядочивания будет в районе 218. Но это уже чисто теоретические предположения.

Следом за очередью декодированных операций располагаются порты запуска и прикрепленные к ним функциональные устройства. На этом этапе остановимся более подробно.

Как мы знаем, у Sandy Bridge было шесть портов запуска, которые он унаследовал от Nehalem, а тот, в свою очередь, от Conroe. То есть с 2006 года, когда Intel добавила еще два порта к имевшимся в распоряжении Рentium 4 четырем, количество портов запуска не менялось - только добавлялись новые функциональные устройства. Правда, стоит оговориться, что P4 имел своеобразную самобытную архитектуру NetBurst, в которой два его порта могли выполнять по две операции за один такт (хотя и далеко не со всеми операциями). Но наиболее правильным будет проследить эволюцию количества портов запуска не на примере P4, а на примере PIII, так как P4 имеет и длинный конвейер, и порты запуска с «удвоенной» производительностью, и кэш трасс, да и вся его архитектура заметно отличается от общепринятной. А Pentium III очень близок по функциональной схеме портов запуска к Conroe, и также имеет короткий контейнер. Так что в общем и целом можно сказать, что Conroe является прямым наследником PIII. Исходя из этого можно заявить, что в 2006 году был добавлен лишь один порт запуска по сравнению с PIII, который имел пять портов запуска.

Таким образом, количество портов запуска растет достаточно медленно, а если уж добавляются новые, то по одному. В Haswell же добавили сразу два, суммарно получив целых восемь портов - еще чуть-чуть, и дойдем до Itanium. Соответственно, Haswell показывает теоретическую производительность на исполнительном тракте в 8 моп/такт, из которых 4 мопа расходуются на арифметические операции, а остальные 4 приходятся на операции с памятью. Напомним, что у Conroe/Nehalem/SB было 6 моп/такт: 3 мопа арифметических операций и 3 мопа операций с памятью. Данное улучшение должно поднять показатель IPC, и, таким образом, в архитектуре Haswell действительно присутствуют очень серьезные изменения, которые вполне оправдывают его место «так» в плане развития Intel.

Изменения ФУ в Haswell

Количество исполнительных устройств также было увеличено. Новый шестой (седьмой по счету) порт добавил два дополнительных исполнительных устройства - устройство целочисленной арифметики и сдвига и устройство предсказания переходов. Седьмой (восьмой) порт отвечает за выгрузку адреса.

Таким образом, мы получаем четыре исполнительных устройства целочисленной арифметики, тогда как Sandy Bridge нам предоставлял только три. Следовательно, можно ожидать увеличения скорости целочисленной арифметики. Кроме того, теоретически это должно нам позволить одновременно выполнять и расчеты с плавающей запятой, и целочисленные расчеты, что, в свою очередь, может увеличить эффективность НТ. В SB вычисления с плавающей запятой осуществлялись на тех же портах, где использовались целочисленные функциональные устройства, поэтому по большому счету происходила блокировка, т. е. нельзя было иметь «разнородную» нагрузку. Также следует отметить, что добавление дополнительного устройства перехода в Haswell позволит предсказывать переход без «блокировки» при арифметических вычислениях - ранее при целочисленных вычислениях единственный предсказатель перехода блокировался, т. е. была возможна работа либо арифметического исполнительного устройства, либо предсказателя. Порты 0 и 1 также претерпели изменения - в них появилась поддержка FMA3. Седьмой (восьмой) порт Intel ввела для увеличения эффективности и снятия «блокировки» - когда второй и третий порты работают на загрузку, седьмой (восьмой) порт может заниматься выгрузкой, что раньше было просто невозможно. Данное решение необходимо для обеспечения высокого темпа исполнения AVX/FMA3-кода.

Вообще, такой широкий исполнительный тракт вполне может привести к изменению HT - сделав ее четырехпоточной. В сопроцессорах Intel Xeon Phi с гораздо более узким исполнительным трактом HT является четырехпоточной, при этом, как показывают исследования и тесты, сопроцессор достаточно хорошо масштабируется. То есть даже более узкий исполнительный тракт в принципе позволяет эффективно работать с четырьмя потоками. А уж тракт с восемью портами запуска вполне эффективно может выполнять четыре потока, и более того, наличие четырех потоков сможет лучше загрузить восемь портов запуска. Правда, для большей эффективности необходимо будет увеличить буферы (в первую очередь - буфер переупорядочивания) для большей вероятности «независимых» данных.

Также в Haswell вдвое увеличили пропускную способность L1-L2, при этом остались прежние величины задержки. Такая мера была просто необходима, так как 32-байтной записи и 16-байтного чтения попросту не хватило бы при наличии восьми портов запуска, а также 256-битных AVX и FMA3.

Sandy Bridge Haswell
L1i 32k, 8-way 32k, 8-way
L1d 32k, 8-way 32k, 8-way
Латентность 4 такта 4 такта
Скорость загрузки 32 байта/такт 64 байта/такт
Скорость записи 16 байт/такт 32 байта/такт
L2 256k, 8-way 256k, 8-way
Латентность 11 тактов 11 тактов
Пропускная способность между L2 и L1 32 байта/такт 64 байта/такт
L1i TLB 4k: 128, 4-way
2M/4M: 8/thread
4k: 128, 4-way
2M/4M: 8/thread
L1d TLB 4k: 128, 4-way
2M/4M: 7/thread
1G: 4, 4-way
4k: 128, 4-way
2M/4M: 7/thread
1G: 4, 4-way
L2 TLB 4k: 512, 4-way 4k+2M shared: 1024, 8-way

TLB L2 был увеличен до 1024 записей, появилась поддержка двухмегабайтных страниц. Увеличение TLB L2 повлекло за собой и увеличение ассоциативности с четырех до восьми.

Что касается кэша третьего уровня, то с ним ситуация неоднозначная: в новом процессоре задержка доступа должна увеличиться из-за потерь при синхронизации, ведь теперь кэш L3 работает на собственной частоте, а не на частоте процессорных ядер, как было раньше. Хотя доступ по-прежнему осуществляется в 32 байта за такт. С другой стороны, Intel говорит об изменениях в System Agent и улучшениях блока Load Balancer, который может теперь обрабатывать параллельно несколько запросов к кэшу L3 и разделять их на запросы к данным и «не-данным». Это должно повысить пропускную способность кэша L3 (некоторые тесты подтверждают это, ПС кэша L3 оказывается чуть выше IB).

Принцип работы кэша L3 в Haswell чем-то схож с Nehalem. У Nehalem кэш L3 находился в Uncore и имел собственную фиксированную частоту, а в SB кэш L3 привязали к процессорным ядрам - его частота стала равна частоте процессорных ядер. Из-за этого возникали проблемы - например, когда процессорные ядра работали на сниженных частотах при отсутствии нагрузки (и LLC «засыпал»), а GPU была необходима высокая ПС LLC. То есть это решение ограничивало производительность GPU, и к тому же требовалось выводить процессорные ядра из состояния простоя лишь для того, чтобы разбудить LLC. В новом процессоре для улучшения ситуации с энергопотреблением и повышения эффективности работы GPU в вышеописанных ситуациях кэш L3 работает на собственной частоте. Наибольшую пользу из этого решения должны извлекать мобильные, а не настольные решения.

Стоит заметить, что объемы кэшей имеют определенную зависимость. Кэша третьего уровня приходится два мегабайта на ядро, кэша второго уровня - 256 КБ, что в восемь раз меньше объема L3 на ядро. Объем кэша первого уровня, в свою очерердь, в восемь раз меньше L2 и составляет 32 КБ. Кэш мопов прекрасно вписывается в эту зависимость: его объем в 1536 мопов в 7-9 раз меньше L1 (точно это определить невозможно, так как битовый объем мопа неизвестен, а Intel вряд ли будет распространяться на эту тему). В свою очередь, буфер переупорядочивания в 168 мопов ровно в восемь раз меньше кэша мопов в 1536 моп, хотя, исходя из повсеместного увеличения буферов и очередей, следовало ожидать увеличения кэша мопов на 14%, то есть до 1776. Таким образом, объемы буферов и кэшей имеют пропорциональные размеры. Это, наверное, еще одна причина, почему Intel не увеличивает кэши L1/L2, считая такие пропорции в объемах наиболее эффективными с точки зрения увеличения производительности на увеличение площади. Стоит заметить, что в процессорах со встроенным топовым графическим ядром присутствует промежуточная быстрая память с широкой шиной доступа, которая кэширует все запросы к оперативной памяти - как процессора, так и видеоускорителя. Объем этой памяти составляет 128 МБ. Для процессорных ядер, если расценивать эту память как кэш L4, объем должен был быть 64 мегабайта, а с добавлением еще и графического ядра использование 128 МБ выглядит вполне логичным.

Что касается контроллера памяти, то он не получил ни увеличения числа каналов, ни увеличения частоты работы с оперативной памятью, то есть это всё тот же контроллер памяти с двухканальным доступом на частоте 1600 МГц. Такое решение выглядит довольно странно, ведь переход с SB на IB увеличил частоту функционирования ИКП с 1333 МГц до 1600 МГц, хотя это был всего лишь переход архитектуры на новый техпроцесс. А сейчас мы имеем новую архитектуру, при этом частота функционирования памяти осталась на прежнем уровне.

Еще более странным это выглядит, если вспомнить об улучшениях в графическом ядре - ведь мы помним, что даже младшая видеокарта HD2500 в IB полностью утилизировала пропускную способность в 25 ГБ/с. Теперь же подросла и производительность ЦП, и производительность графики, а пропускная способность памяти осталась на прежнем уровне. Если взглянуть более широко, то конкурент постоянно увеличивает пропускную способность памяти в своих гибридных процессорах, и она выше, чем у Intel. Логично было ожидать в Haswell поддержку памяти с частотой 1866 МГц или 2133 МГц, что повысило бы пропускную способность до 30 и 34 ГБ/с соответственно.

Как итог, данное решение Intel не совсем понятно. Во-первых, конкурент ввел поддержку более быстрой памяти без особых проблем. Во-вторых, стоимость модулей памяти, функционирующих на частоте 1866 МГц, ненамного выше по сравнению с 1600-мегагерцовыми модулями, к тому же никто не обязывает покупать 1866-мегагерцовую память - выбор оставался бы за пользователем. В-третьих, никаких проблем с поддержкой не то что 1866 МГц, но и 2133 МГц быть не может: с самого анонса Haswell были поставлены мировые рекорды разгона оперативной памяти, то есть ИКП без проблем «потянул» бы более быструю память. В-четвертых, в серверной линейке Xeon E5-2500 V2 (Ivy Bridge-EP) заявлена поддержка 1866 МГц, а ведь Intel обычно внедряет поддержку более быстрых стандартов памяти на этом рынке много позже настольных решений.

В принципе, можно было бы предположить, что в отсутствие конкуренции Intel нет необходимости «просто так» наращивать мускулы и еще больше увеличивать превосходство, но данное предположение абсолютно некорректно, так как увеличение пропускной способности памяти, как правило, увеличивает производительность встроенного графического ядра и почти не увеличивает производительность процессора. При этом Intel пока отстает от AMD именно в производительности графики, и в последние годы сама же Intel всё больше и больше уделяет внимание именно графике, и темпы улучшений для нее гораздо выше, чем для процессорного ядра. Кроме того, если опираться на результаты тестирований встроенного графического ядра предыдущего поколения HD4000, которые показали, что увеличение ПСП приводит к увеличению производительности графики до 30%, а также учитывая, что новое графическое ядро HD4600 заметно быстрее, чем HD4000, то зависимость производительности графического ядра от ПСП становится еще более явной. Новое графическое ядро будет еще больше упираться в «узкую» пропускную способность памяти. Суммируя все факты, решение Intel совершенно непонятно: компания собственноручно «задушила» свою графику, а ведь увеличение ПСП могло бы подтянуть ее производительность.

Возвращаясь к архитектуре кэшей, выскажем просто мысль в пустоту: раз уж был добавлен промежуточный кэш (кэш мопов), то почему бы не добавить еще промежуточный кэш данных объемом порядка 4-8 КБ и с меньшей задержкой доступа между кэшем L1d и исполнительными устройствами, как у P4 (раз уж концепция кэша мопов была взята именно у Netburst)? Напомним, что в P4 этот промежуточный кэш данных имел время доступа в два такта, причем один такт Р4 был равен примерно 0,75 тактам обычного процессора, то есть время доступа было около полутора тактов. Впрочем, может быть, мы еще увидим что-то подобное - Intel любит вспоминать хорошо забытое старое.

Как можно было заметить, большинство архитектурных изменений Intel направила на увеличение производительности кода AVX/FMA3: это и увеличение пропускной способности кэшей, и увеличение количества портов, и увеличение темпа выгрузки/загрузки в исполнительном тракте. В итоге, основной выигрыш в производительности должен быть именно в ПО, написанном с использованием AVX/FMA3. В принципе, судя по результатам тестов, похоже, что так оно и есть. Сухая производительность на одинаковой частоте в «старых» приложениях получила прирост около 10% по сравнению с предыдущим ядром, а приложения, написанные с использованием новых наборов инструкций, показывают прирост более 30%. Так что преимущества архитектуры Haswell будут раскрываться по мере оптимизации приложений под новые наборы инструкций. Вот тогда превосходство Haswell над SB станет очевидным.

Основной выигрыш от значительной части нововведений получат мобильные устройства. Им помогут и новый подход к кэшу L3, и встроенный регулятор напряжения, и новые режимы сна, и более низкие минимальные частоты функционирования процессорных ядер.

Заключение (процессорная часть)

Чего можно ожидать от Haswell?

В связи с увеличением количества портов запуска можно ожидать увеличения показателя IPC, поэтому небольшое преимущество у новой архитектуры Haswell над Sandy Bridge на одинаковой частоте будет уже сейчас, даже при неоптимизированном программном обеспечении. Инструкции AVX2/FMA3 - это задел на будущее, и это будущее зависит от разработчиков ПО: чем быстрее они адаптируют свои приложения, тем быстрее конечный пользователь получит прирост производительности. Однако не стоит рассчитывать на рост всего и везде: SIMD-инструкции в основном используются в работе с мультимедийными данными и в научных расчетах, так что роста производительности стоит ожидать именно в этих задачах. Основной выигрыш от увеличения энергоэффективности получат мобильные системы, где этот вопрос действительно важен. Таким образом, два основных направления, по которым новая архитектура Intel Haswell существенно выигрывает - это увеличение SIMD-производительности и увеличение энергоэффективности.

Что касается применимости новых процессоров Haswell, то стоит разобрать несколько разных вариантов их применения: в настольных компьютерах, в серверах, в мобильных решениях, для геймеров, для оверклокеров.

Десктоп

Энергопотребление не является ключевым аспектом для десктопного процессора, поэтому даже в Европе с ее дорогой электроэнергией вряд ли кто-то будет переходить на Haswell с предыдущих поколений только из-за этого. Тем более, что TDP у Haswell выше, чем у IB, так что экономия будет лишь в случае минимальных нагрузок. При такой постановке вопроса сомнений быть не может - оно того не стоит.

С точки зрения производительности переход тоже не выглядит таким уж выгодным делом: максимальный прирост скорости в процессорных задачах сейчас составит не более 10%. Переход на Haswell с Sandy Bridge или Ivy Bridge будет оправдан только в том случае, если вы планируете использовать приложения с грамотной поддержкой FMA3 и AVX2: поддержка FMA3 может дать прирост в некоторых приложениях от 30% до 70%. Улучшения, связанные с виртуализацией и внедрением транзакционной памяти, для десктопа малоинтересны и малополезны.

Серверы и рабочие станции

Учитывая, что серверы работают непрерывно все 24 часа в сутки и имеют достаточно высокую постоянную нагрузку на процессор, по чистому энергопотреблению Haswell вряд ли будет лучше IB, хотя по производительности на ватт и может дать некоторый выигрыш. Поддержка AVX2/FMA3 вряд ли пригодится в серверах, а вот в рабочих станциях, занимающихся научными расчетами, данная поддержка будет весьма и весьма полезна - но лишь при условии поддержки новых инструкций в применяемом ПО. Транзакционная память - вещь достаточно полезная, но тоже не всегда: она может дать прирост в многопоточных программах и в программах, работающих с базами данных, но для ее эффективного использования также необходима оптимизация ПО.

А вот все улучшения, связанные с виртуализацией, скорее всего дадут неплохой эффект, так как виртуальные среды сейчас используются очень активно, и на большинстве физических серверов работает по несколько виртуальных. Причем распространенность виртуализации объясняется не только заметным снижением издержек виртуальной среды в плане производительности, но и экономической эффективностью: содержать много виртуальных серверов на одном физическом и дешевле, и позволяет более эффективно использовать ресурсы, в том числе ресурсы процессора.

Так что на серверном рынке появление Haswell должны встретить положительно. После смены серверов на базе Xeon E3-1200v1 и Xeon E3-1200v2 на серверы с Xeon E3-1200v3 (Haswell) вы сразу получите прирост эффективности, а после оптимизации ПО под AVX2/FMA3 и транзакционную память производительность подрастет еще сильнее.

Мобильные решения

Основной выигрыш от внедрения Haswell в мобильном сегменте, конечно же, лежит в сфере улучшенного энергопотребления. Судя по презентациям Intel, а также результатам тестов, которые уже появляются в Сети, эффект действительно есть, и заметный.

Что касается чистой производительности, то переход с Ivy Bridge на Haswell не представляется таким уж обоснованным мероприятием: чистый прирост должен быть отностительно небольшим, а улучшения в отдельных компонентах (те же виртуализация или мультимедийные инструкции) вряд ли много дадут пользователю мобильной системы, так как на ноутбуках и планшетах редко занимаются созданием сред или сложными научными расчетами.

В общем и целом, с точки зрения процессорной производительности многого ждать не стоит, зато в мобильных системах наверняка будет востребован рост производительности графического ядра. Поэтому если вопросы энергопотребления для вас не критически важны, то серьезно рассматривать вопрос апгрейда с Sandy Bridge или Ivy Bridge не стоит - лучше продолжать эксплуатировать имеющиеся системы, пока они окончательно не устареют. Если же вы часто работаете от батарей, то Haswell способен обеспечить существенный прирост времени автономной работы.

Геймеры

Вопрос энергопотребления у геймеров в России, как правило, не стоит - да и с чего бы ему стоять, когда геймерские видеокарты потребляют по 200 и более ватт? Виртуализация и транзакционная память геймеру тоже не нужны. Не факт, что AVX2/FMA3 будут востребованы именно для игр, хотя они могут пригодиться в расчетах физики. Остается чистая производительность процессора, а тут разница с тем же Ivy Bridge невелика. Как итог, для этой категории пользователей прямой переход с SB или IB на Haswell также не выглядит актуальным. Зато разумно переходить на новые процесоры с Nehalem и Lynifield, и уж тем более Conroe.

Оверклокеры

Для оверклокеров новый процессор (но, конечно, лишь его «разблокированная» K-версия) может быть интересен, особенно если удастся его «скальпировать», то есть снять металлическую крышку и охлаждать кристалл напрямую. Если этого не сделать, то результаты по разгону выглядят еще более скромными, чем у Ivy Bridge. Плюс, сдерживающим фактором может стать интегрированный регулятор напряжения. Подробнее об этом читайте

Временами у программистов возникает жгучее желание прочитать что-то из базы данных. Программисты становятся нервными и раздражительными, теряют сон и лихорадочно тыкают пальцами в клавиатуру. Ради всеобщего блага и мира во всем мире рассмотрим несложную работу с базой данных из C# с помощью ADO.NET и OLE DB. Хотя данный механизм поддерживает разные базы данных вроде Oracle, здесь и сейчас будем использовать MS SQL Server.

Две основных задачи при работе с базой данных

2. Выполнение sql-команды, что-то делающей на сервере (insert, update, delete, вызов функции или хранимой процедуры

3. Последовательное чтение из select-выборки строки за строкой. В основном используется в веб-приложениях, в настольных проще скачать сразу всю выборку в оперативную память, экономия от чтения только нужных строк незначительна.

4. Редкий случай. Автоматическое обновление таблицы в базе на основании изменений в DataTable (как правило редактируемой через визуальный интрфейс). В реальной жизни данные обычно читаются через сложный запрос с кучей join или представление, так что автоматическая синхронизация не подходит.

Основные классы, используемые для этих целей: OleDbConnection - соединение с базой, создаем со строкой, содержащей параметры соеднинения, открываем, закрываем, OleDbCommand - создаем с экземпляром соединения и sql-командой, если нужно просто выполнить update или получить единичное значение, то хватит этого класса, OleDbDataAdapter - создается с OleDbCommand, специализируется на разовом чтении наборов строк в DataTable, может автоматически создавать колонки DataTable на основании выборки, переносить изменения из DataTable в таблицу в базе, OleDbDataReader - последовательное чтение строк в DataTable по одной за раз (он работает внутри OleDbDataAdapter), DataTable / DataSet - основной контейнер для данных. В перечислении OleDbType хранятся типы данных базы данных.

Using System.Data; using System.Data.OleDb; // строка соединения, используется система пользователей Windows (Integrated Security=SSPI;) string connString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=databaseName;Data Source=serverName"; // альтернативная строка соединения с иcпользованием аутентификации MS SQL Server // connString = "Provider=SQLOLEDB.1;Persist Security Info=False;Initial Catalog=databaseName;Connect Timeout=20;Data Source=serverName;Uid=userName;Pwd=userPassword;" OleDbConnection dbConn = new OleDbConnection(connString); dbConn.Open(); someDataTable = new DataTable(); OleDbDataAdapter dbAdapter = new OleDbDataAdapter("select COLUMN1, COLUMN2 from TEST_TABLE ORDER BY COLUMN2", dbConn); // внутренняя структура пустой таблицы будет создана автоматически на основании прочитанных данных, если структура таблицы уже задана (например через типизированный DataSet), то данные будут писаться в столбцы с совпадающими именами или добавятся новые столбцы dbAdapter.Fill(someDataTable); // альтернативный вариант для заполнения таблицы в DataSet // dbAdapter.Fill(someDataSet, "someDataTable"); dbConn.Close();

2. Выполнение sql-команды, что-то делающей на сервере (insert, update, delete, вызов функции или хранимой процедуры .

Особенно стоить отметить проблемы с датами. Реализация дат в.Net крайне кривая - изначально даты не могут быть пустыми, а реальной жизни они пустые сплошь и рядом. Самое правильное решение - использовать специальный класс даты, исправляющий косяки программистов из Microsoft. Более ленивые разработчики держат все даты в коде строками и конвертируют их в DateTime только при необходимости, например при записи в базу или DataTable. Nullable DateTime не спасает, так как пустая дата в интерфейсе должна выглядеть пустой строкой, а при записи в базу как DBNull.Value - и банальный null в коде не конвертируется в эти значения без дополнительных плясок с бубном.

Первый вариант подразумевает банальное склеивание строки запроса. Считается плохой практикой и особенно опасен в веб-приложениях, так как уязвим для хакерских атак. Проблема с пустыми датами так просто не решается. Кроме того при работе с датами появляется дополнительная проблема - разные форматы строк даты в зависимости от региональный настроек.Net Framework, среды разработки и sql-сервера. Выглядеть это может сюрреалистически - один и тот же запрос работает в SQL Managment Studio, но вылетает при выполнении из кода. Частично спасает особый формат строки дат, Тем не менее так нередко делают в маленьких программках для внутреннего пользования, о существовании которых внешний мир никогда не узнает.

OleDbCommand dbCommand = dbConn.CreateCommand(); dbCommand.CommandText = "INSERT INTO TEST_TABLE (INT_COLUMN, VARCHAR_COLUMN, DATETIME_COLUMN) VALUES (" + intVariable", " + stringVariable" , " + dateTimeVariable.ToString("yyyyMMdd") +")"; dbCommand.ExecuteNonQuery();

Правильный вариант подразумевает создание команды с набором строго типизированных параметров. Считайте, что предыдущего абзаца не было.

OleDbCommand dbCommand = dbConn.CreateCommand(); dbCommand.CommandText = "INSERT INTO TEST_TABLE (INT_COLUMN, VARCHAR_COLUMN, DATETIME_COLUMN) VALUES (?, ?, ?)"; dbCommand.Parameters.Add("INT_COLUMN", OleDbType.Integer).Value = intVariable; dbCommand.Parameters.Add("VARCHAR_COLUMN", OleDbType.VarChar).Value = stringVariable; if (stringDate == "") { dbCommand.Parameters.Add("DATETIME_COLUMN", OleDbType.DateTime).Value =DBNull.Value; } else { dbCommand.Parameters.Add("DATETIME_COLUMN", OleDbType.DateTime).Value = Convert.ToDateTime(stringDate); } dbCommand.ExecuteNonQuery();

Хранимая процедура вызывается точно так же, разнообразия ради другой вариант записи значений в параметры (он не связан именно с хранимой процедурой):

OleDbCommand someDbComm = new OleDbCommand("someStoredProcedure", this.dbConn); someDbComm.CommandType = CommandType.StoredProcedure; someDbComm.Parameters.Add("@parameter1", OleDbType.VarChar); someDbComm.Parameters.Add("@parameter2", OleDbType.VarChar); someDbComm.Parameters.Value = "У всякой проблемы всегда есть решение - про­стое, удобное и, конечно, ошибочное"; someDbComm.Parameters.Value = "Генри Луис Менкен"; someDbComm.ExecuteNonQuery();

Расширенный вариант описания параметра с указанием размера поля и привязкой к конкретной колонке таблицы.

DbCommand.Parameters.Add("VARCHAR_COLUMN", OleDbType.VarChar, 100, "VARCHAR_COLUMN").Value = stringVariable;

Если нам не нужна привязка параметра команды к определенному полю DataTable, то лучше всего не указывать размер вообще, так например если строка будет меньше указанной длинны Varchar, то добрый.Net фреймворк добавит в строку пробелов до указанной длины, испортив передаваемые на сервер данные.

Значение единичного поля читается методом ExecuteScalar()

OleDbCommand dbCommand = dbConn.CreateCommand(); dbCommand.CommandText = "SELECT TEST_COLUMN FROM TEST_TABLE WHERE ID_COLUMN = ?"; dbCommand.Parameters.Add("INT_COLUMN", OleDbType.Integer).Value = intVariable; int result = Convert.ToInt32(dbCommand.ExecuteScalar());

Надо особо отметить, что ExecuteScalar возвращает Object и если запрос не вернул вообще ничего, то результат будет null и конвертация в нормальный тип данных вылетит с ошибкой. Если возможна ситуация, когда в ответ мы ничего не получим, то надо делать так:

OleDbCommand dbCommand = dbConn.CreateCommand(); dbCommand.CommandText = "SELECT TEST_COLUMN FROM TEST_TABLE WHERE ID_COLUMN = ?"; dbCommand.Parameters.Add("INT_COLUMN", OleDbType.Integer).Value = intVariable; object resultObj = dbCommand.ExecuteScalar() int result = -1; // значение по умолчанию, означающее пустой результат if(resultObj != null) { result = Convert.ToInt32(dbCommand.ExecuteScalar()); }

3. Последовательное чтение из select-выборки строки за строкой
Чтение одной строки (несколько читаются в цикле);

OleDbCommand dbCommand = new OleDbCommand(select PERSON_ID, NAME, SURNAME from TEST_TABLE, dbConn); OleDbDataReader dbReader = dbCommand.ExecuteReader(); dbReader.Read(); string name = Convert.ToString(dbReader["NAME"]); string surname = Convert.ToString(dbReader["SURNAME"]); dbReader.Close();

4. Редкий случай. Автоматическое обновление таблицы в базе на основании изменений в DataTable (как правило редактируемой через визуальный интерфейс).

Необходимо прописать для DbAdapter четыре команды на каждый возможный случай - select, insert, update, delete.

DbAdapter.InsertCommand = new OleDbCommand("insert into TEST_TABLE (NAME, FAMIL, AGE) values (?, ?, ?)", dbConnection); dbAdapter.InsertCommand.Parameters.Add("NAME", OleDbType.VarChar, 100, "NAME"); dbAdapter.InsertCommand.Parameters.Add("FAMIL", OleDbType.VarChar, 100, "FAMIL"); // для типов данных с неизменной длинной указанная в команде длинна игнорируется dbAdapter.InsertCommand.Parameters.Add("AGE", OleDbType.Integer, 100, "AGE"); // добавляем команду обновления dbAdapter.UpdateCommand = new OleDbCommand("update TEST_TABLE set NAME = ?, FAMIL = ?, AGE = ? where ID = ?", dbConnection); dbAdapter.UpdateCommand.Parameters.Add("NAME", OleDbType.VarChar,100, "NAME"); dbAdapter.UpdateCommand.Parameters.Add("FAMIL", OleDbType.VarChar, 100, "FAMIL"); dbAdapter.UpdateCommand.Parameters.Add("AGE", OleDbType.Integer, 100, "AGE"); dbAdapter.UpdateCommand.Parameters.Add("ID", OleDbType.Integer, 100, "ID"); // добавляем команду удаления dbAdapter.DeleteCommand = new OleDbCommand("delete from TEST_TABLE where ID = ?", dbConnection); dbAdapter.DeleteCommand.Parameters.Add("ID", OleDbType.Integer, 100, "ID"); try { // переносит все изменения из DataTable в таблицу в базе данных dbAdapter.Update(table); } catch (Exception error) { MessageBox.Show("Ошибка при сохранении данных! " + error.Message); return; } MessageBox.Show("Изменения сохранены!");

Было упомянуто всего несколько слов о том, что в состав Провайдера
Данных (Data Provider) входит объект Соединение (Connection ).
В данной статье мы рассмотрим этот объект более подробно, выясним его роль в
ADO.NET, основные свойства и методы.
Назначение объекта Connection
поддерживать физическую связь между хранилищем данных и приложением.NET.
Поскольку, как мы уже знаем, в составе ADO.NET имеется два Провайдера Данных, а
каждый из них имеет собственную реализацию объекта Connection, нам придется
рассмотреть обе разновидности.

OLE DB .NET Data Provider включает в себя OleDbConnection
(пространство имен System.Data.OleDB ), а SQL Server .NET Data
Provider, соответственно, - SqlConnection (пространство имен
System.Data.SqlClient
). Хотя различия между ними не столь
радикальны, тем не менее, их следует иметь в виду при переносе приложений на
другое хранилище данных.

Как упоминалось ранее, SqlClient работает с
хранилищем данных напрямую, поэтому при работе с Microsoft SQL Server 7.0 и
выше предпочтительнее использовать SQL Server .NET Data Provider и SqlConnection ,
поскольку это обеспечит более высокую эффективность работы приложения.

Как создать соединение?

Те, кто работает в интерактивной среде разработки Visual
Studio .NET, наверное, уже привыкли к тому, что в ней имеется большой набор
«мастеров», которые облегчают труд программиста, выполняя за него
обременительную рутинную работу. Не является исключением и создание Connection .

Те, кто проповедует аскетизм.NET Framework (или вынужден
довольствоваться им поневоле), могут пропустить этот раздел и перейти к
следующему, в котором описывается программное создание Connection.

Создание Connection посредством Server Explorer

В состав Visual Studio .NET входит весьма ценный инструмент –
Server Explorer, который позволяет во время разработки устанавливать соединения
с различными службами, включая журналы, очереди сообщений и т.д., а также с
источниками данных, что сейчас представляет для нас наибольший интерес.

Попробуем создать Соединение при помощи Server Explorer. Для
этого сначала создадим проект приложения Windows. Затем убедимся, что панель
Server Explorer доступна (если нет, включить ее можно посредством меню View
->Server Explorer). Выглядит она примерно таким образом:


Такая же кнопка имеется в меню Tools:


После нажатия на кнопку появляется окно «Свойства связи с
данными», хорошо знакомое тем, кто уже имеет опыт работы в ADO:


Попробуем создать соединение с базой данных «Борей», которая
поставляется в качестве примера вместе с Microsoft Access различных версий и
наверняка присутствует на подавляющем большинстве компьютеров, на которых
установлен Microsoft Office. Для этого:


    переходим на страницу «Поставщик данных»;


    выбираем из списка «Поставщики OLE DB» строку «Microsoft Jet
    4.0 OLE DB Provider»


Примечание. Microsoft Jet – это ядро базы данных, которое
Microsoft использует как основу для Access, а также в составе ряда других
продуктов (например, для хранения электронной корреспонденции в Exchange
Server). С помощью провайдера Microsoft Jet 4.0 OLE DB Provider можно получить
доступ к данным, хранящимся в базах данных, созданных посредством Access.



  • жмем кнопку «Далее >>» или переходим на страницу
    «Подключение»;

нажав на кнопку с многоточием «…», выбираем полный путь к
файлу базы данных (или вводим вручную, если есть желание); у меня он выглядит
так: C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb;


если на вашей системе база данных «Борей» защищена паролем,
введите его в соответствующем поле; если вы желаете, чтобы пароль для доступа к
базе данных хранился месте с другими данными о соединении, установите опцию
«Разрешить сохранение пароля» (разумеется, это нежелательно, если содержимое
базы не должно быть открыть для несанкционированного доступа);


    для проверки работоспособности нажмите кнопку «Проверить
    подключение»; если все сделано правильно, вы увидите результат:



Если по какой-либо причине подключение к базе данных не может
быть выполнено, вы получите сообщение об ошибке вроде следующего:


В этом случае проверьте правильность введенного пути к файлу
базы данных и, возможно, уточните пароль;


    если проверка подключения к базе данных прошла успешно,
    нажмите кнопку «OK» окна «Свойства связи с данными»;


    на панели Server Explorer появляется новое соединение с
    базой данных «Борей»:



Посредством Server Explorer мы можем не только исследовать
структуру таблиц, видов, хранимых процедур и прочих объектов базы данных, но и
получить доступ к их содержимому. Например, двойной щелчок левой кнопкой мыши
на значке таблицы открывает ее содержимое для просмотра и даже редактирования в
среде Visual Studio .NET.


    теперь осталось создать объект Connection, который позволит
    нашей программе установить соединение с базой данных «Борей»; для этого
    буксируем пиктограмму соединения с панели Server Explorer на форму нашего
    приложения.


На этом работа по созданию объекта Connection
завершена! Под формой приложения появился значок:


Это и есть объект типа System.Data.OleDb.OleDbConnection ,
который мы стремились получить. При необходимости имя объекта можно изменить
при помощи панели свойств.

Обратите особое внимание на то, что соединение, созданное
посредством Server Explorer, не является частью текущего проекта, а хранится
вместе с настройками среды Visual Studio .NET. На мой взгляд, это имеет как
положительные, так и отрицательные стороны.

К положительным сторонам относится то, что соединение может
быть использовано во множестве проектов. К отрицательным – то, что, поскольку
соединение не является частью проекта, то при его передаче кому-нибудь другому
или при продолжении работы над ним на другом компьютере информация о настройке
соединения передана не будет.

Итак, подведем итог проделанной работе. В результате наших
действий на панели Server Explorer появилось соединение с базой данных «Борей»,
которое посредством буксировки мышью было помещено на форму нашего приложения.
Появилась соответствующая пиктограмма, при ее выборе мышью свойства объекта
Connection видны на панели свойств Проверка кода программыпоказывает, что среди
объектов формы появился новый
private System.Data.OleDb.OleDbConnection oleDbConnection1;
а в методе InitializeComponent появились строки:
this.oleDbConnection1 = new System.Data.OleDb.OleDbConnection();

// oleDbConnection1

This.oleDbConnection1.ConnectionString =

Source=C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb;Mode=Share
Deny None;Extended Properties="""";Jet OLEDB:System database="""";Jet
OLEDB:Registry Path="""";Jet OLEDB:Database Password="""";Jet OLEDB:Engine
Type=5;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk
Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database
Password="""";Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt
Database=False;Jet OLEDB:Don"t Copy Locale on Compact=False;Jet OLEDB:Compact
Without Replica Repair=False;Jet OLEDB:SFP=False";
Мы видим, что помимо создания объекта OleDbConnection ,
его свойству ConnectionString присвоено значение в
виде довольно-таки длинной строки. Что означает сия конструкция, мы
разберем немного позже, а пока рассмотрим альтернативные способы создания
объекта Connection .

Примечание. Для полноты изложения стоит упомянуть, что помимо
панели Server Explorer, с Connection можно также работать и посредством ссылок
на базу даннах (Database References) из панели Solution Explorer Visual Studio
.NET. Однако подробно на этом останавливаться не будем, поскольку этот вопрос
скорее относится к работе IDE, а не к функциональности Connection ADO.NET.

Программное создание Connection

Разумеется, как и практически любой объект в Visual Studio
.NET, создаваемый посредством вызова «мастера», экземпляр объекта Connection
можно создать и программным путем. Особенно полезным такой способ является при
создании консольных приложений.NET, поскольку «мастер» создает экземпляр
Connection
при буксировании его на форму приложения, а отсутствие
самой формы делает такой подход непригодным.
Вряд ли для читателя будет неожиданностью, что для создания
Connection
нужно вызвать конструктор. Обе разновидности Connection
имеют два перегруженных варианта конструктора: с пустым списком параметров () и
с единственным параметром (ConnectionString ), который задает
строку подключения (и опять откладываем разъяснение, что же это такое).

Пример программного создания Connection :

Public SqlConnection cnnTest = new SqlConnection();
(разумеется, предполагается, что в программе предварительно
было объявлено, что используется пространство имен System.Data.SqlClient ).

Свойства Connection

Прежде всего во избежание возможных недоразумений замечу, что
при рассмотрении свойств, методов и событий я рассматриваю в первую очередь те,
которые являются собственными для данного класса (это относится к Connection
и будет относиться к классам, рассматриваемым в следующих статьях). Помимо них,
классы имеют свойства, методы и события, унаследованные от родительских
классов. Если унаследованные члены класса не имеют непосредственного отношения
к нашей основной тематике, а именно – работе с базами данных посредством
ADO.NET, я их рассматривать не буду, чтобы не загромождать статью
несущественными деталями. В то же время имейте в виду, что данные классы могут
иметь и другие члены, кроме упомянутых мной.

Для управления соединением с источником данных из программы
объект Connection , разумеется, имеет набор свойств и методов.
Рассмотрим подробнее свойства обеих реализаций объекта.

Название Описание Тип Доступ OLE DB SQL Значение по умолчанию
ConnectionString Строка соединения System.String RW + +
ConnectionTimeout Время ожидания соединения в секундах System.Int32 R + + 15 сек
Database Имя текущей базы данных (или той, которая будет использоваться при открытии соединения) System.String R + +
DataSource Имя сервера баз данных (SQL) или спецификация файла с данными System.String R + +
PacketSize Размер сетевого пакета в байтах System.Int32 R - + 8192
Provider Имя провайдера OLE DB System.String R + -
ServerVersion Версия сервера баз данных System.String R + +
State Битовая комбинация значений ConnectionState ConnectionState R + + Closed
WorkstationId Строка, идентифицирующая клиента System.String R - + Имя клиентского компьютера

Примечания:


    В графе «Доступ» RW обозначает запись и чтение, R – только
    чтение.


    В графах «OLE DB» и «SQL» указано наличие данного свойства
    для OleDbConnection и SqlConnection ,
    соответственно. «+» – свойство поддерживается, «-» – не поддерживается.


    В графе «Значение по умолчанию прочерк «–» для свойств типа
    System.String
    означает пустую строку.


    Перечислены только собственные свойства объекта, без учета
    свойств, наследуемых от Component.


Те, кто знаком с классическим ADO, наверное, удивятся,
заметив, что все свойства, кроме ConnectionString , отныне
доступны только для чтения. Да, это действительно так. Все параметры соединения
в ADO.NET задаются исключительно через строку соединения . Возможно, это
и к лучшему, поскольку пропадает соблазн попытаться их изменить во время
выполнения программы, что зачастую приводит к исключительной ситуации при
открытом соединении.

Обратите внимание на небольшое различие в свойствах OleDbConnection
и SqlConnection . Хотя основной набор их одинаков, все же
некоторые специфичны для провайдера. SqlConnection имеет
уникальные свойства PacketSize и WorkstationId ,
а OleDbConnection – свойство Provider . Это
может негативно повлиять на переносимость программ на другую платформу.

Следует избегать задания свойству ConnectionTimeout
нулевого значения, т.к. оно соответствует бесконечному тайм-ауту и может
привести к зависанию приложения.

Значение свойства Database может изменяться в
ходе выполнения приложения, если оно меняет текущую базу данных (либо
соответствующим оператором SQL, либо вызовом метода ChangeDatabase ).

Значение свойства PacketSize может быть
задано в диапазоне от 512 до 32767 байт. При пересылке больших объемов данных
увеличение размера пакета может повысить производительность, т.к. уменьшает
количество небходимых операций чтения/записи пакетов.

Свойство State может принимать значения из
перечисления ConnectionState . Эти значения следующие:

В данное время из этого набора значений допустимыми являются только Open
и Closed .

Строка соединения (Connection String)

Наконец-то пришла пора рассказать о том, что же такое
представляет собой строка соединения. Этот термин уже упоминался ранее. Однако
предмет достаточно сложен и должен быть рассмотрен подробнее.

Свойство ConnectionString является, пожалуй,
основным свойством Connection . Все остальные свойства, как мы
видели ранее, доступны только на чтение и передают значение одного из
параметров, задаваемых в строке соединения.

Строка соединения представляет собой текстовую строку
специального вида. Она состоит из пар вида «ключ=значение», разделенных
символом «точка с запятой» (;).

«Ключ» не зависит от регистра и может задаваться как на
верхнем, так и на нижнем регистрах; «значение» в общем случае зависит от
регистра.

Допустимо повторение «ключа» несколько раз в строке. В этом
случае используется последнее вхождение, остальные игнорируются. Ошибкой такое
повторение не является.

Содержимое строки специфично для конкретного провайдера.
Обычно для построения корректной строки во время проектирования программы
полезно бывает воспользоваться следующей уловкой: создать соединение при помощи
Server Explorer (мы уже умеем это), а затем скопировать строку соединения из
его свойств.

Значение свойства ConnectionString можно
задавать только при закрытом соединении ! После установки Connection
анализирует строку и устанавливает значения остальных свойств в соответствии с
ее содержимым. Впрочем, полный анализ содержимого строки соединения
производится только в момент открытия Connection . Если при
этом встретится неподдерживаемое имя ключа или недопустимое значение, будет
сгенерировано соответствующее исключение (OleDbException или
SqlDbException
).

Объект Connection реализует интерфейс IDbConnection ,
поэтому для доступа к общим свойствам обоих провайдеров можно объявить
переменную типа IDbConnection . Это позволит немного смягчить
проблему неполной совместимости двух провайдеров данных.

Методы Connection

К счастью, методы SqlConnection и OleDbConnection
совершенно одинаковы.

Наиболее важными, пожалуй, являются Open и
Close
. Они могут вызываться как явно, так и неявно, другими
компонентами ADO.NET. Если метод Open вызывается компонентами
DataAdapter
или DataCommand (которые мы рассмотрим
в следующих статьях), то они оставляют Connection в начальном
состоянии, т.е. если Connection был открыт, то ничего не
меняется, а если закрыт – то вызывающий компонент открывает его, выполняет
требуемую операцию, а затем закрывает. Таким образом, программист может
игнорировать побочные эффекты этих компонентов.

Открытое соединение не закрывается автоматически при
уничтожении объекта Connection
! Необходимо помнить, что
открытое соединение потребляет ресурсы как рабочей станции, так и
сервера-источника данных. Поэтому следует взять за правило явно закрывать
соединение посредством вызова Close и делать это как можно
раньше, как только соединение больше не требуется. При закрытии соединения
Close
откатывает все незавершенные транзакции.

BeginTransaction – перегруженная функция,
возвращающая объект-транзакцию (различные для разных провайдеров). Думаю,
сейчас обсуждать вопрос реализации транзакций преждевременно, поскольку в
теоретическом курсе мы еще не рассмотрели, что это такое.

CreateCommand создает объект Datacommand ,
который мы еще не рассматривали. Поэтому нам придется пока довольствоваться
этим скудным описанием. Смысл данной операции станет ясен позже.

Пул соединений

Для более экономного использования ресурсов ADO.NET работает с
пулом соединений. SQL Server .NET Data Provider имеет собственный пул
соединений, а OLE DB .NET Data Provider использует пул OLE DB. Управлять пулом
можно соответствующими параметрами строки соединения, но подробное рассмотрение
этого вопроса выходит за рамки статьи.

Для начала достаточно знать, что пул соединений – это некое
хранилище готовых к употреблению соединений. По умолчанию пул соединений
разрешен, и при закрытии соединения через Close оно на самом
деле не закрывается физически, а помещается в пул. Если при попытке открыть
новое соединение через Open обнаруживается, что такое готовое
соединение есть в пуле, оно не создается, а просто выдается приложению из пула.
Поскольку на установление соединения требуется время, которое для удаленного
сервера может оказаться весьма ощутимым, использование пула может существенно
ускорить работу приложения.

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

События connection

Эти события немногочисленны, их всего два, и они совпадают для
обоих вариантов Connection .

StateChange возникает при изменении состояния
Connection, т.е. когда его свойство State меняет значение с
Open
на Closed или наоборот. Обработчик этого
события получает аргумент типа StateChangeEventArgs , который
имеет два свойства: OriginalState (исходное состояние
соединения) и CurrentState (его текущее состояние). Оба эти
свойства могут принимать одно из значений перечисления ConnectionState ,
которое мы уже рассмотрели ранее при изучении свойства State .

InfoMessage возникает, когда источник данных
возвращает предупреждение или информационное сообщение. Оба варианта соединения
возвращают коллекцию ошибок, текстовое описание ошибки и имя объекта, в котором
возникла ошибка. OleDbConnection.InfoMessage имеет
дополнительное свойство ErrorCode , которое идентифицирует
источник ошибки в соответствии со стандартом ANSI SQL.

Итоги

Итак, подведем итог, чему мы научились в этой статье.

Прежде всего – весьма, на мой взгляд, важный факт, про который
не следует забывать. Имеется две реализации Connection – для
OLE DB и MS SQL Server. Эти реализации довольно похожи, но не идентичны.
Поэтому на начальном этапе разработки следует определиться, чем пожертвовать –
эффективностью или переносимостью, так как в дальнейшем может потребоваться
переделка программы.

Объект Connection необходим для установления
связи с источником данных. Другие объекты используют Connection
для обмена информацией с источником данных, при этом некоторые из них требуют,
чтобы соединение было явно открыто, другие способны управлять его состоянием
самостоятельно.

Если разрабатывается типичное приложение на основе диалога,
создать соединение можно как вручную, так и воспользоваться услугами
специального мастера. При разработке консольного приложения выбора не остается
– только создание программного соединения вручную, т.к. при работе мастера
соединение буксируется на форму приложения.

Основное свойство Connection – это ConnectionString ,
именно в нем задаются все параметры, необходимые для установления соединения.
Все остальные свойства, кроме State , являются производными и
возвращают значения отдельных параметров соединения, но изменять их можно
только через ConnectionString.

Задать корректное значение ConnectionString
задача не из легких. Неоценимую помощь в ее формировании может оказать мастер
установки соединений, даже если само соединение планируется устанавливать
программно.

Любые изменения параметров соединения можно производить только
тогда, когда оно закрыто. Исключением является текущая база данных, которую
можно изменить при открытом соединении вызовом метода ChangeDatabase .

При изменении состояния соединения возникает событие StateChange ,
а при получении предупреждения или информационного сообщения – событие InfoMessage .

Заключение

И наконец в закрепление знаний, полученных нами о соединениях ADO.NET, приведу
небольшую программу, которая способна открывать и закрывать соединения с
учебной базой данных (кнопки "Open"
и
"Close" ), а также показывать состояние и свойства соединения
(кнопка "Show" ). Программа может быть откомпилирована и выполнена в среде
Visual Studio .NET или.NET Framework.

При выполнении программы на вашем компьютере обратите внимание
на следующие моменты, которые, на мой взгляд, наиболее наглядны:


    Попытка открыть уже открытое соединение приводит к ошибке. Поэтому при открытии
    соединения в сомнительных случаях либо проверяйте его состояние (свойство
    State
    ), либо перехватывайте исключение InvalidOperationException .
    К закрытию закрытого соединения ADO.NET относится гораздо лояльнее и ошибки
    времени выполнения не возникает.


    Не все свойства Connection доступны при закрытом соединении, в
    чем вы можете убедиться, нажав кнопку
    при закрытом соединении. Впрочем, вряд ли кому-то понадобятся свойства
    закрытого соединения.


Код программы-примера для этой статьи:

Using System;

Using System.Windows.Forms;

Using System.Data;

Namespace ConnSample

{
public class frmConnSample: System.Windows.Forms.Form

{
private System.Windows.Forms.Button btnExit;
private System.Windows.Forms.Button btnOpen;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Label lblConnState;
private System.Windows.Forms.TextBox txtConnstate;
private System.Data.OleDb.OleDbConnection oleDbCnn1;
private System.Windows.Forms.Button btnShow;
private System.Windows.Forms.ListBox lstConnProps;
private System.ComponentModel.Container components = null;

Public frmConnSample()
{
InitializeComponent();
}

Protected override void Dispose(bool disposing
{
if(disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code
private void InitializeComponent()
{
this.btnExit = new

this.oleDbCnn1 = new
System.Data.OleDb.OleDbConnection();
this.btnOpen = new
System.Windows.Forms.Button();
this.btnClose = new
System.Windows.Forms.Button();
this.lblConnState = new
System.Windows.Forms.Label();
this.txtConnstate = new
System.Windows.Forms.TextBox();
this.btnShow = new
System.Windows.Forms.Button();
this.lstConnProps = new
System.Windows.Forms.ListBox();
this.SuspendLayout();
// btnExit
this.btnExit.Location = new
System.Drawing.Point(296, 232);
this.btnExit.Name = "btnExit";
this.btnExit.TabIndex = 0;
this.btnExit.Text = "Exit";
this.btnExit.Click += new
System.EventHandler(this.btnExit_Click);
// oleDbCnn1
// строка подключения; подкорректируйте ее
согласно размещению файлов на вашем компьютере
this.oleDbCnn1.ConnectionString =
@"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";User ID=Admin;Data
Source=C:\Program Files\Microsoft Office\Office10\Samples\Борей.mdb";
// добавляем обработчик события StateChange
this.oleDbCnn1.StateChange += new
System.Data.StateChangeEventHandler(this.ShowConnState);
// btnOpen
this.btnOpen.Location = new
System.Drawing.Point(16, 232);
this.btnOpen.Name = "btnOpen";
this.btnOpen.TabIndex = 2;
this.btnOpen.Text = "Open";
this.btnOpen.Click += new
System.EventHandler(this.btnOpen_Click);
// btnClose
this.btnClose.Location = new
System.Drawing.Point(104, 232);
this.btnClose.Name = "btnClose";
this.btnClose.TabIndex = 3;
this.btnClose.Text = "Close";
this.btnClose.Click += new
System.EventHandler(this.btnClose_Click);
// lblConnState
this.lblConnState.Location = new
System.Drawing.Point(16, 200);
this.lblConnState.Name = "lblConnState";
this.lblConnState.Size = new
System.Drawing.Size(96, 16);
this.lblConnState.TabIndex = 4;
this.lblConnState.Text = "Connection state:";
// txtConnstate
this.txtConnstate.Location = new
System.Drawing.Point(112, 200);
this.txtConnstate.Name = "txtConnstate";
this.txtConnstate.TabIndex = 5;
this.txtConnstate.Text = "";
// btnShow
this.btnShow.Location = new
System.Drawing.Point(296, 200);
this.btnShow.Name = "btnShow";
this.btnShow.TabIndex = 6;
this.btnShow.Text = "Show";
this.btnShow.Click += new
System.EventHandler(this.btnShow_Click);
// lstConnProps
this.lstConnProps.Location = new
System.Drawing.Point(16, 16);
this.lstConnProps.Name = "lstConnProps";
this.lstConnProps.Size = new
System.Drawing.Size(344, 173);
this.lstConnProps.TabIndex = 7;
// frmConnSample
this.AutoScaleBaseSize = new
System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(384,
266);
this.Controls.AddRange(new
System.Windows.Forms.Control

{
this.lstConnProps,
this.btnShow,
this.txtConnstate,
this.lblConnState,
this.btnClose,
this.btnOpen,
this.btnExit
});
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false; this.MinimizeBox =
false; this.Name = "frmConnSample";
this.Text = "Connection Sample";
this.ResumeLayout(false);
}
#endregion


static void Main()
{
Application.Run(new frmConnSample());
}

Private void btnExit_Click(object sender, System.EventArgs
e)
{
Application.Exit();
}

Private void btnOpen_Click(object sender, System.EventArgs
e)
{
try
{
oleDbCnn1.Open();
}
catch (InvalidOperationException err) // попытка
открыть уже открытое соединение
{
MessageBox.Show("Connection is
already open!!!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (System.Data.OleDb.OleDbException err)
{
MessageBox.Show("Error opening
Connection!!!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

Private void btnClose_Click(object sender, System.EventArgs
e)
{
oleDbCnn1.Close();
}

Private void btnShow_Click(object sender, System.EventArgs
e)
{
try
{
lstConnProps.Items.Clear();

LstConnProps.Items.Add("ConnectionString = " + oleDbCnn1.ConnectionString);

LstConnProps.Items.Add("ConnectionTimeout = " +
oleDbCnn1.ConnectionTimeout.ToString());
lstConnProps.Items.Add("Database = "
+ oleDbCnn1.Database);
lstConnProps.Items.Add("DataSource =
" + oleDbCnn1.DataSource);
lstConnProps.Items.Add("Provider = "
+ oleDbCnn1.Provider);

LstConnProps.Items.Add("ServerVersion = " + oleDbCnn1.ServerVersion);
lstConnProps.Items.Add("State = " +
oleDbCnn1.State);
}
catch (System.InvalidOperationException err)
{
MessageBox.Show("Cannot get some
properties of the closed Connection!!!", "Warning", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}

// индикатор текущего состояния соединения
private void ShowConnState(object sender,
StateChangeEventArgs e)
{
txtConnstate.Text = oleDbCnn1.State.ToString();
}
}
}



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows