Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Enitity Framework и Using


Подскажите, а является ли нормальной практикой плодить контексты using при работ
с Enitity Framework или правильнее передавать объекты сущностей в методы в качестве аргументов?

Вот это я подразумеваю под "Плодить контексты": 

DoWork()
{
    using (var db = new Entity())
    {
        // какая-то работа с сущностью
        ...
        DoWork2();
        ...
        // какая-то работа с сущностью
    }
}

DoWork2()
{
    using (var db = new Entity())
    {
        // какая-то работа с сущностью
        ...
    }
}

    


Ответы

Ответ 1



У многих, кто использует EF, возникает вопрос, как часто мы должны создавать DbContext, как определить оптимальное время жизни контекста. Возможные варианты времени жизни контекста: Функция Форма Поток Приложение Чтобы сделать правильный выбор, предлагаю рассмотреть несколько аспектов: Правильное разрушение контекста (вызов метода Dispose() контекста) Вызов метода Dispose является важным шагом при работе с классом DbContext. Используя конструкцию using, гарантируетcя своевременный вызов метода Dispose и тем самым освобождение неуправляемых ресурсов. using (MyContext ctx = new MyContext()) { … } Если забыть вызвать Dispose, то это может привести к утечке открытых соединений к БД и к неосвобождению неуправляемых ресурсов. do-i-have-to-call-dispose-on-dbcontext Стоимость операции создания нового класса контекста Операция создания нового контекста недорогая, потому что это, в основном, копировани ссылок метаданных из глобального кеша. Поэтому за стоимость этой операции не стоит беспокоиться. Использование памяти Чем дольше вы используете объект DbContext, тем больше памяти он занимает. Потом что он будет содержать все сущности (entity), о которых он знает, которые были запрошены через запросы, были добавлены либо присоединены. Поэтому держать долго контекст не рекомендуется. Потокобезопасность Класс DbContext не является потокобезопасным. Если мы используем контекст из нескольких потоков, то мы сами должны обеспечить сихронизацию доступа к контексту. Синхронизация данных с базой данных После создания контекста, если не предпринимать дополнительные меры, контекст н видит изменённые данные в БД, которые были сделаны извне. Создавая новый контекст, меры по синхронизации данных с БД предпринимать не нужно. Вот основные аспекты, которые пришли в голову. Поэтому контексты с коротким времене жизни при работе с EF являются нормальной практикой и часто используются при работе с EF.

Ответ 2



Context в EF, это, по сути, готовая реализация сразу нескольких паттернов: Repository Data Mapper Lazy Load ... Identity Map Unit of Work Последние два существенно ограничивают возможные варианты времени жизни контекста: Unit of Work Maintains a list of objects affected by a business transaction and coordinate the writing out of changes and the resolution of concurrency problems. Identity Map An Identity Map keeps a record of all objects that have been read from the databas in a single business transaction. Whenever you want an object, you check the Identity Map first to see if you already have it. Из двух цитат выше напрямую следует что контект должен жить ровно одну бизнес-операцию: Если он будет жить меньше ("плодить контексты" в вопросе) - то часть кода операции не увидит измененения, внесенные до нее. Если он будет жить дольше, на протяжении нескольких операций - то другие операци будут видеть неактуальные данные (из-за Identity Map) или наоборот, будт видеть изменения, которые еще не были сохранены. Что такое бизнес-операция (бизнес-транзакция) - зависит от конкретной предметно области. Это не транзакция в терминах баз данных, а более широкое понятие - некое целостное действие в терминах предметной области. Обычно это вызов кода сервиса / фасада в BL - DoWork, где Work - это какая-то цельная операция, действие. Т.е. обычно это вызов функции верхнего уровня в вашем приложении. Соображения использования памяти, потокобезопасности, стоимости создания, синхронизаци с базой данных - полностью вторичны, и не должны служить основанием для выбора времени жизни контекста. Контекст - это попытка отразить в коде цельную операцию из предметной области. Предметно области все равно, сделаете вы это в одном потоке или в разных, потратите при этом мног памяти или мало, придется ли вам при этом писать огромные методы, или обойдеться парой строк - это никак не влияет на целостность операции. Соответственно, и на выбор времени жизни контекста влиять не должно. Выбор контейнера в коде, в рамках которого живет контектст - функция, форма, поток запрос, приложение - тоже вторичен. Он должне быть следствием, а не причиной времени жизни контекста. Если конкретная функция (DoWork) соответствует бизнес-операции - она должна контролировать время жизни контекста. Если нет (DoWork2) - то нет. Если бизнес-операция растягивается на время отображения формы - то время жизни контекста должно совпадать с формой, и контекст вполне может быть полем формы. Если нет - то нет. Если вы запускаете фоновые операция в отдельном потоке - то время жизни скорее всег совпадет с временем жизни потока. Но не потому, что это фоновая операция, а потому что это фоновая операция. Если у вас консольное приложение, которое выполняет ровно одну бизнес-операцию то вполне разумно использовать один контекст на приложение.

Ответ 3



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

Собеседование по алгоритмам - как подготовиться к нему за одну неделю? [закрыт]


Здравствуйте.

Примерно через неделю мне предстоит собеседование по алгоритмам.

У меня незаконченное математическое образование, что означает, что я знаю, что такое
например, логарифм или факториал, но при этом совершенно не имею академической подготовк
по этой теме (толкового курса по программированию и по этой теме в частности в течение 3 лет, что я учился, не было). Мой суммарный опыт программирования - 4 года. Основные языки в настоящее время Objective-C и C.

Я пытаюсь продумать оптимальную стратегию для подготовки и поэтому интересуюсь: може
ли кто-нибудь набросать что-то вроде обзора этой темы "Алгоритмы" (quick overview), ориентируясь на который можно было бы более или менее направленно успеть за неделю пройти самые-самые основные в этой теме вопросы?

Вот навскидку то, что мне известно в связи с этой темой (точнее о чём имею боле
или менее чёткое представление, список неисчерпывающий):


O-notation
Хорошо знаю примерно треть алгоритмов из этого репозитория: EKAlgorithms и даже кое-чт
добавил туда сам, например, алгоритмы Indexes of maximum and minimum elements simultaneously, Quickselect, Partial selection sort, алгоритм бинарного поиска.
Например, хорошо теперь знаком с geo-spatial структурами и алгоритмами вроде: KD-деревья и двумерные K-деревья в частности, Quad-деревья, алгоритмами Grid clustering и K-means.
Например, хорошо знаю, как устроены массивы и словари в C и Objective-C, включа
circular buffer (который лежит в основе массивов NSMutableArray у Apple).
...


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

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

Буду благодарен за законченные, целостные и сбалансированные ответы, которые помогу
мне или другим потенциальным читателям этого топика, так как, уверен, тема эта актуальна всегда и везде. 

P.S. Особо интересно было бы увидеть ответ @VladD.



Хороший соседний топик (из ответа @VladD) - Алгоритмическая "база" хорошего программиста. Вопрос по саморазвитию.



Спасибо.
    


Ответы

Ответ 1



По этой теме как-то было обсуждение: Алгоритмическая "база" хорошего программиста. Вопрос по саморазвитию. Приведу выжимку, которая мне кажется важной и подходит для креш-курса: Сложность алгоритмов, O-нотация, нужно уметь сходу оценивать O-сложность алгоритма хотя бы для простых случаев. Туда же Θ-нотация. Структуры данных: деревья, обходы их, trie, куча, разрежённые матрицы и всё такое. Про них любят спрашивать. Сортировки. Про них, скорее всего, не спросят, так как все знают и готовятся. Но всё же. Графы, различные их представления и работа с ними. Поиск в ширину и в глубину, алгоритм Дейкстры и A*. Обязательно попрактикуйтесь с разными задачами. Алгоритмы могут означать некую олимпиадну составляющую, но туда лучше не заглядывать, очень уж специфическая область умений (если вы только сами не оттуда). На интервью не бойтесь сказать, что вы чего-то не знаете. (Это всё равно довольн сложно скрыть.) Но останавливаться и проваливать часть интервью не стоит, просто скажите, что вы попытаетесь сходу что-нибудь придумать. Ну и попробуйте придумать, это зачтётся. Мне кажется, не стоит тратить последнюю неделю на поиск и усвоение новых знаний новый багаж должен утрястить, прежде чем вы сможете его эффективно использовать. Поэтому лучше систематизируйте имеющиеся знания, если есть видимые пробелы (например, та же «амортизированна сложность» в hashtable), заполните их. Вероятно, имеет смысл задать их отдельными вопросами здесь и на математике. прогоните хорошую серию задач, чтобы чувствовать себя уверенно. настройтесь на то, что не только работа нужна вам, но и вы — работе: адекватный работодател возьмёт вас, если увидит, что вы интересуетесь темой и растёте над собой (даже если каких-то знаний на момент интервью нет), а неадекватный вам и не нужен.

Ответ 2



Ну вы ж информируйте нас о том, как идёт подготовка, хорошо? Пришло время написать немного о подготовке и результатах - конечно же я собиралс это сделать и уже давно, просто ждал пока придёт ответ от компании. Теперь ответ пришёл, и я могу теперь спокойно закрывать гештальт. Расскажу в нескольких частях. Ничего интересного не обещаю. Особенно более опытным, чем я, участникам ХК. Итак, I. Материалы и источники, которыми я пользовался. Книга Cracking the code interview, 5th edition. Лекции Яндекса: "Алгоритмы и структуры данных поиска. Бабенко Максим Александрович." (торрент) Видео-курс "Robert Sedgewick, Kevin Wayne - Algorithms"(торрент) и их книга Algorithms (fourth edition). Репозиторий с простейшими алгоритмами на Objective-C: EKAlgorithms, одним из контрибьюторо которого я являюсь. В основном я больше привношу в этот репозиторий, чем беру из нег - среди прочего я постоянно добавляю варианты к уже существующим там алгоритмам и добавля к ним тесты так, чтобы можно было легко проверять как уже имеющиеся варианты, так и новые варианты и легко сравнивать их между собой, в том числе по производительности. Кроме того, я стараюсь максимально оптимизировать и гуманизировать (humanize) все находящиеся там алгоритмы, чтобы их можно было легко и быстро адаптировать для использования в реальных Objective-C/Cocoa программах. II. Подготовка. Подготовка происходила сумбурно и, имея в виду разумное напутствие VladD: Мне кажется, не стоит тратить последнюю неделю на поиск и усвоение новых знаний новый багаж должен утрястить, прежде чем вы сможете его эффективно использовать... (и далее весь раздел) Я посмотрел первые три лекции Яндекса: "Сложность и модели вычислений", "Анализ учётны стоимостей", "Функции быстрой сортировки и сортировки слиянием". Там я впервые узнал например, про тета- и гамма- нотацию. Также внимательно слушал про "анализ учётных стоимостей (амортизированная стоимость, метод банкира и др.). Послушал про сортировки - сравнение основных методов, стабильность, in-place, итд. Например, впервые узнал, но почти ничего усвоил - только смутное представление - про сортировку внешних данных External memory Merge Sort и K-way merge. Прочитал около сотни страниц Cracking the code interview - особой пользы практическо в связи с алгоритмами я, конечно, не получил, но зато появилось некоторое представлени о том, что там происходит в компаниях "большой шестёрки" с точки зрения code interviews. Например, среднее количество собеседований в этих компаниях примерно 6-8 штук, но это все кроме меня тут наверняка знают. Посмотрел выборочно несколько видео-лекций из курса Седжвика про сортировки и особенн остановился на его разборе быстрой сортировки - видео мне показалось мало, и я прогляде ещё и книгу, раздел про Quick Sort. Среди прочего удивило то, что только в 1990 год некий инженер из Bell Labs заметил, что quick sort начинает работать очень затратн на последовательностях с большим количеством одинаковых ключей (у него это были нули и единицы), и только после этого qsort в stdlib был исправлен для того, чтобы это учесть. Сюда же утверждение Серджвика о том, что в начале нужно делать рандомайз всего массива, чтобы гарантировать беспорядок, чтобы было N * log N. Словом, было интересно, и я все эти моменты отметил. Во время прослушивания лекции Яндекса про merge sort меня привлекла идея о том, чт при слиянии двух кусков можно обойтись N / 2 дополнительной памяти (external storage вместо N (я думаю все кроме меня тут в курсе, о чём речь). Меня это сильно увлекло и я решил закрепить этот принцип на практике и тут же поправил процедуру построения К-деревьев в библиотеке kingpin - там используется немного другая идея, но аналогия была очень точной и получилось сделать то самое сокращение temporary storage в 2 раза. Я квалифицирую это приключение, как решение задачи в количестве 1 штука в духе прогоните хорошую серию задач, чтобы чувствовать себя уверенно. как советовал @VladD. Меня давно заинтересовала задача Иосифа (Josephus Problem), и я в течение двух-трё дней из этой недели небольшими подходами пробовал решить её в качестве ещё одной и задач для разминки перед собеседованием. Признаюсь честно, сделать efficient-верси с O(K * log N) вместо O(N) ума не хватило даже совсем приблизительно, от чего до сих пор есть чувство собственной неполноценности - хватило только на наивную версию (как в Википедии) и версию, в которой используется "итератор-убийца" - она работает медленно, но зато позволяет хорошо визуализировать ход того, как происходят убийства. Повторно изучал очень хороший, основанный на дизассемблировании, разбор того, ка внутри устроен класс NSMutableArray - это класс для мутабельных массивов в Cocoa. В его основе лежит Circular buffer, но кроме этого простого факта в статье содержится ещё несколько деталей, которые очень полезно знать именно Objective-C разработчикам. Добавил некоторое число алгоритмов в EKAlgorithms (главным образом, сортировки) поправил реализацию уже существующих там (написанных не мной), написал несколько тестов для того, чтобы проверить некоторые нюансы изучаемого материала. Так как кроме собеседования по алгоритмам ожидалось ещё одно собеседование по iOS то я готовился ещё и по теме iOS - читал все основные источники в основном по двум темам: Run loops, Autorelease pools. Основное вроде всё описал, двигаюсь дальше. III. Собеседование. Перед самым собеседованием настроение было такое, что меня уничтожат вопросами пр деревья, графы, матрицы, про многочисленные изобретения Эдсгера Дейкстры и прочее. Вышл же всё совсем просто, хотя я всё равно 1! раз умудрился продемонстрировать незнание самых простых именно азбучных основ [из-за их отсутствия я собственно и открывал этот вопрос пару недель назад]. Итак: Первым вопросом было рассказать о общем о том, как измеряются сложность и эффективность алгоритмов. Я рассказал самые простые и тривиальные вещи. Вопрос был общий и простой. Дальше было уточнение про O-нотации. Я тоже рассказал всё в общем адекватно и, как мне кажется, хорошо. Следующим был задан вопрос про то, что именно обозначает O-нотация (подразумевалос в сравнении с тета-, гамма-) - тут я честно застрял, так как эти детали у меня совершенн вылетели из головы - я честно признался, что помню лишь, что одна из них "сверху", другая "снизу", третья "снизу и сверху", но какая из них какая, не знаю чётко. Считаю это главным своим недочётом во всём собеседовании. Был вопрос именно про то, что мы обсуждали здесь про lg N, а именно: "А какой именн логарифм имеется в виду, когда говорится о логарифмической сложности?". Я конечно ж рассказал всё то, что мы успели затронуть здесь - и о строгой математической нотаци и о том, что log2 и lg асимптотически отличаются друг от друга на константу, о том, что скорее всего lg N просочилось в массовое употребление с подачи нескольких классических работ по алгоритмам. Словом, ответ был очень развёрнутый. Можно считать это замечательным совпадением, так как открывался этот топик в том числе для ответа на этот вопрос - "почему встречается lg N, если имеется в виду log N или точнее log2 N?". Дальше был общий вопрос рассказать про Quick Sort - я тут же восторженно рассказа обо всём, что с большим интересом наизучал по видео и книге Седжвика и своим эксперимента с имплементацией всего им описанного: про 1990 год, про рандомайз, чтобы убрать худши случаи, про откат к insertion sort'у на малом числе элементов. Как мне показалось, свои рассказом я "грузанул" своего собеседователя так, что следующим, что он предложил, было написать "что-нибудь попроще" на его компьютере в коллабедите (в котором присутствовал также второй собеседователь) простой Bubble Sort, что я и сделал мгновенно с использованием лаконичных Cocoa API. Меня попросили прокомментировать написанное, что я и сделал. Всё было правильно. Дальше вступил второй собеседователь и спросил про худшие случаи для Bubble Sor и спросил, как можно их смягчить. Я сходу, по следам рассказа про худшие случаи в Quic Sort, ответил, что если такие худщие и редкие для Bubble Sort случаи действительно ожидаются можно делать перед началом сортировки рандомайз. Мой ответ устроил спрашивающего, н он спросил: "А ещё?". Я подумал некоторое время и понял, что сходу сказать не смог (я всегда в таких случаях точно могу оценить, сколько времени мне точно не хватит для решения задачи, и это был такой случай). Оба собеседователя сошлись на "ладно, хорошо" и попросили рассказать на словах про Selection Sort и Insertion Sort. Я чётко рассказал про Selection Sort и начал рассказывать про Insertion Sort - начав немного путаться, я попросил времени подумать. Первый собеседователь сказал: "ладно, у нас остаётся мало времени, давайте решим задачу". Задача оказалась такой: есть генератор random01(), который в случайном порядке выдаё нули или единицы. Нужно на его основе написать random0123(), который выдаёт случайные 0 или 1 или 2 или 3. Не успев даже подумать про первый и второй биты целого числа, в каждый из которы записывается по random01() (это понимание уже пришло после собеседования), я сразу увиде геометрическую аналогию с задачей про выбор квадранта, которую мы недавно разбирал с @avp, @paulgri, @VladD и @mega, и тут же сказал, что нужно просто взять random01( два раза в две переменные, а потом использовать двойное ветвление, и показал собеседовател эту геометрическую аналогию. Я сказал, что будет честно считать, что я эту задачу зна и что можно попробовать решить какую-нибудь ещё. Он спросил меня, "а как сделать на основе random01() троичный random012()?", то есть как из 2 получить 3 случайных числа, а не 4, как в первой задаче, но тут нас начали выгонять из переговорной. Я решил эту задачу уже дома, и понял, что будь на собеседовании больше времени, я бы не догадался о решении за отведённое малое время. Я отправил своему собеседователю это решение просто как follow-up, так как всегда выполняю нерешённые задачи в качестве "домашнего задания". Вот и всё. P.S. А итог такой, что меня не взяли. Причины отказа не назвали, сославшись: "У нас н принято сообщать о причинах отказов" и только: "Фидбэк о вас очень положительный, но продолжить общение мы не сможем". Было 4 собеседования: 1) Вводное с ведущим разработчиком. Про это рассказывать долго, отмечу основное: Я очень грамотно рассказал о наивных имплементациях NSMutableArray, NSMutableDictionar в том виде, как они описаны Mike Ash в его известных постах "Let's build NSMutableArray и "Let's build NSMutableDictionary" - я очень хорошо знаю эти реализации с С массиво позади NSArray и простейшим словарём позади NSDictionary, так как делал кое-какие вещи на их основе. В процессе рассказа был вопрос про амортизированную стоимость - я на тот момент об этом не знал совершенно, даже слов таких не слышал, о чём и сказал прямо. Кстати, это "жесткое незнание" было одной из причин открытия этого вопроса. Ещё была простейшая задача на матрицу вида N * N, которую я не решил в отведённо время, запутавшись с индексами - я не предложил ответ, а так и сказал, что запутался Это наверное, был единственный серьёзный прокол за все 4 собеседования. Мой ответ собеседовател был такой: "я чётко понимаю, что мне нужно больше времени на эту задачу, в пределах этого времени у меня нет решения". В самом деле, придя домой, я решил эту задачу за 5 минут, так как в этой задаче для её быстрого решения нужно было "всего лишь" догадаться об одной очевидной мелочи (кавычки потому что "эх, если б сразу, вовремя"). 2) Собеседование по iOS. Типичные вопросы. Отмечу некоторые: Вопросы про разницу instancetype и init. Написать геттеры/сеттеры к данным @property (под MRC) NULL, nil, Nil, NSNull - кто такие, и в чём разница. Вопрос про блоки, в котором подразумевается знание о необходимости копировать блоки, чтобы копировать их содержимое на heap. Проверка на знание Cocoa-паттерна: (void)aMethod:(NSError * __autoreleasing *)error { // do stuff, possibly assigning error if something went wrong } 3) Алгоритмы (о них я рассказал выше). 4) "Архитектура". Я предполагал, что это будут вопросы про архитектуру, то есть устройств iOS, оказалось, что это собеседование про проектирование - меня спросили как спроектироват библиотеку для единой авторизации, которую смогут использовать несколько родственных между собой мобильных приложений. Чуть позже выяснилось, что мои собеседователи в этом интервью сами как раз являются разработчиками этой функциональности для всей экосистемы мобильных приложений в этой компании. P.S. №2 Не уверен, зачем я написал этот длинный пост. Наверное цели три две: люблю печатно слово первая - закрыть для себя вопрос с большим первым раундом подготовки по теме алгоритмы вторая - возможно, вдруг кому-то хоть как-то написанное окажется интересным или полезным - лично я, пожалуй, был бы не прочь прочитать такой текст перед началом собственной подготовки к аналогичной цепи собеседований.

Ответ 3



Вдобавок к ответу @VladD: Деревья: балансировка деревьев Комбинаторика: способы оценки трудоемкости алгоритмов (отсюда и вытекает О-нотация) Матрицы: обращение треугольной матрицы, обращение 2-3-х диагональных матриц (это хит) Олскульные ребята (вроде меня) обожают вопросы связанные с решением задач на экономи ресурсов (обычно память): кэширование, рекурсия vs. массив, LRU списки, битовые маски, хэши и проч. Поищите в сети книжку Cracking Coding Interview - полезно полистать.

Ответ 4



Советую прочесть книгу - Карьера программиста. Она небольшая но очень познавательная и полезная в данном вопросе.

Атомарные и неатомарные операции (java)


Как понять, какие операции являются атомарными, а какие неатомарными?

Вот что я нашла на Хабре:


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


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

Один шаг == одной машинной операции? Или чему-то другому? Как определить точно, какие операции относятся к атомарным, а какие к неатомарным?

P.S.: Я нашла похожий вопрос, но там речь идёт о C#...  
    


Ответы

Ответ 1



Как можно определить атомарность? Атомарность операции чаще всего принято обозначать через ее признак неделимости операция может либо примениться полностью, либо не примениться вообще. Хорошим примером будет запись значений в массив: public class Curiousity { public volatile int[] array; public void nonAtomic() { array = new int[1]; array[0] = 1; } public void probablyAtomic() { array = new int[] { 1 }; } } При использовании метода nonAtomic существует вероятность того, что какой-то пото обратится к array[0] в тот момент, когда array[0] не проинициализирован, и получит неожиданно значение. При использовании probablyAtomic (при том условии, что массив сначала заполняется а уже потом присваивается - я сейчас не могу гарантировать, что в java это именно так но представим, что это правило действует в рамках примера) такого быть не должно: array всегда содержит либо null, либо проинициализированный массив, но в array[0] не может содержаться что-то, кроме 1. Эта операция неделима, и она не может примениться наполовину, как это было с nonAtomic - только либо полностью, либо никак, и весь остальной код может спокойно ожидать, что в array будет либо null, либо значения, не прибегая к дополнительным проверкам. Кроме того, под атомарностью операции зачастую подразумевают видимость ее результат всем участникам системы, к которой это относится (в данном случае - потокам); это логично, но, на мой взгляд, не является обязательным признаком атомарности. Почему это важно? Атомарность зачастую проистекает из бизнес-требований приложений: банковские транзакци должны применяться целиком, билеты на концерты заказываться сразу в том количестве в котором были указаны, и т.д. Конкретно в том контексте, который разбирается (многопоточност в java), задачи более примитивны, но произрастают из тех же требований: например, если пишется веб-приложение, то разбирающий HTTP-запросы сервер должен иметь очередь входящих запросов с атомарным добавлением, иначе есть риск потери входящих запросов, а, следовательно, и деградация качества сервиса. Атомарные операции предоставляют гарантии (неделимости), и к ним нужно прибегать, когда эти гарантии необходимы. Кроме того, атомарные операции линеаризуемы - грубо говоря, их выполнение можно разложит в одну линейную историю, в то время как просто операции могут производить граф историй, что в ряде случаев неприемлимо. Почему примитивные операции не являются атомарными сами по себе? Так же было бы проще для всех. Современные среды исполнения очень сложны и имеют на борту некислый ворох оптимизаций которые можно сделать с кодом, но, в большинстве случаев, эти оптимизации нарушают гарантии Так как большинство кода этих гарантий на самом деле не требует, оказалось проще выделит операции с конкретными гарантиями в отдельный класс, нежели наоборот. Чаще всего в приме приводят изменение порядка выражений - процессор и JVM имеют право выполнять выражения не в том порядке, в котором они были описаны в коде, до тех пор, пока программист не будет форсировать определенный порядок выполнения с помощью операций с конкретными гарантиями. Также можно привести пример (не уверен, правда, что формально корректный) с чтением значения из памяти: thread #1: set x = 2 processor #1: save_cache(x, 2) processor #1: save_memory(x, 2) thread #2: set x = 1 processor #2: save_cache(x, 1) processor #2: save_memory(x, 1) thread #1: read x processor #1: read_cache(x) = 2 // в то время как х уже был обновлен значением в thread #2 Здесь не используется т.н. single source of truth для того, чтобы управлять значение Х, поэтому возможны такие аномалии. Насколько понимаю, чтение и запись напрямую в память (или в память и в общий кэш процессоров) - это как раз то, что форсирует модификатор volatile (здесь могу быть неправ). Конечно, оптимизированный код выполняется быстрее, но необходимые гарантии никогда не должны приноситься в жертву производительности кода. Это относится только к операциям связанным с установкой переменных и прочей процессорной сфере деятельности? Нет. Любая операция может быть атомарной или неатомарной, например, классически реляционные базы данных гарантируют, что транзакция - которая может состоять из изменени данных на мегабайты - либо применится полностью, либо не будет применена. Процессорны инструкции здесь не имеют никакого отношения; операция может быть атомарной до тех пор, пока она является атомарной сама по себе или ее результат проявляется в виде другой атомарной операции (например, результат транзакции базы данных проявляется в записи в файл). Кроме того, насколько понимаю, утверждение "инструкция не успела за один цикл - операци неатомарна" тоже неверно, потому что есть некоторые специализированные инструкции, и никто не мешает атомарно устанавливать какое-либо значение в памяти на входе в защищенный блок и снимать его по выходу. Любая ли операция может быть атомарной? Нет. Мне очень сильно не хватает квалификации для корректных формулировок, но, наскольк понимаю, любая операция, подразумевающая два и более внешних эффекта (сайд-эффекта) не может быть атомарной по определению. Под сайд-эффектом в первую очередь подразумеваетс взаимодействие с какой-то внешней системой (будь то файловая система или внешнее API), но даже два выражения установки переменных внутри synchronized-блока нельзя признать атомарной операцией, пока одно из них может выкинуть исключение - а это, с учетом OutOfMemoryError и прочих возможных исходов, может быть вообще невозможно. У меня операция с двумя и более сайд-эффектами. Могу ли я все-таки что-нибудь с этим сделать? Да, можно создать систему с гарантией применения всех операций, но с условием, чт любой сайд-эффект может быть вызван неограниченное число раз. Вы можете создать журналируемую систему, которая атомарно записывает запланированные операции, регулярно сверяется с журналом и выполняет то, что еще не применено. Это можно представить следующим образом: client: journal.push {withdrawMoney {card=41111111, cvc=123}, reserveTicket {concert=123}, sendEmail {address=nobody@localhost}} client: <журнал подтвердил получение и запись задания> journal: process withdrawMoney journal: markCompleted withdrawMoney journal: process reserveTicket journal: <умирает, не успев записать выполнение reserveTicket> journal: <восстанавливается> journal: process reserveTicket # сайд-эффект вызывается еще раз, но только в случае некорректной работы journal: markCompleted reserveTicket journal: process sendEmail journal: markCompleted sendEmail Это обеспечивает прогресс алгоритма, но снимает все обязательства по временным рамка (с которыми, формально говоря, и без того не все в порядке). В случае, если операции идемпотентны, подобная система будет рано или поздно приходить к требуемому состоянию без каких-либо заметных отличий от ожидаемого (за исключением времени выполнения). Как все-таки определить атомарность операций в java? Первичный источник правды в этом случае - это Java Memory Model, которая определяет какие допущения и гарантии применяются к коду в JVM. Java Memory Model, впрочем, довольн сложна для понимания и покрывает значительно большую сферу операций, нежели сфера атомарны операций, поэтому в контексте этого вопроса достаточно знать, что модификатор volatile обеспечивает атомарное чтение и запись, а классы Atomic* позволяют производить compare-and-swap операции, чтобы атомарно менять значения, не боясь, что между чтением и записью придет еще одна чья-то запись, а в комментариях ниже на момент прочтения наверняка добавили еще что-то, что я забыл.

Ответ 2



Как понять, какие операции являются атомарными, а какие неатомарными? Рискуя на себя навлечь обвинения в сексизме, таки не удержусь и приведу пример атомарно операции: беременность - операция строго атомарная, всегда есть один и только один отец (всякие генные ухищрения вынесем за скобки). И наоборот пример неатомарной операции: воспитание ребенка - увы операция неатомарная ребенок есть к сожалению субъект множества различных несинхронизированных операций над неокрепшей душой ребенка: мама, папа, бабушка, дедушка, зомбоящик, детсад, школа, друзья, подруги и т.д. по списку.

Ответ 3



Попробую объяснить. Могу ошибаться. Есть java, исходники компилируются в байткод. Байткод во время выполнения программ преобразуется в машинный код. Одна инструкция/команда в байткоде может преобразоватьс в несколько инструкций машинного кода. В этом и заключается проблема атомарности. Процессо не может за раз выполнить одну команду, написанную на языке высокого уровня: он выполняет машинный код, содержащий последовательность команд. Следовательно, если разные процессоры выполняют манипуляции над одними и теми же данными, то различные инструкции процессоров могут чередоваться. Приведу пример: Есть глобальная переменная: public volatile int value = 0; first-thread { value++ } second-thread{ value++ } Инкрементирование переменной не является атомарной операцией: оно требует, как минимум, три инструкции: прочитать данные увеличить на единицу записать данные Соответственно, два потока должны выполнить эту последовательность, но порядок и выполнения между ними не определен. Из-за этого и могут возникнуть ситуации вроде следующей: Первый поток прочел данные Второй поток прочел данные Первый поток увеличил значение на 1 Второй поток увеличил значение на 1 Второй поток записал значение Первый поток записал значение В результате имеем результат 1, а не 2 как ожидалось. Чтобы такого не происходило, используют либо синхронизацию, либо атомарные примитивы из пакета java.util.concurrent

Не получается решить задачу на программирование: калькулятор


Пытаюсь решить задачу условие, которой приведено ниже.
Проблема в том что на больших числах моя программа выдает какой-то совершенно адски
результат. К примеру для числа 96234 программа выдает такую простыню чисел http://pastebin.com/8H5SvPK
(сравните с тем результатом, который приведен в условии). В принципе я понимаю почему так происходит, но другой идеи для решения данной задачи у меня нет. Подскажите как тут грамотно решить эту задачу.

Условие задачи:

У вас есть примитивный калькулятор, 
который умеет выполнять всего три операции с текущим числом x: 
заменить x на 2x, 3x или x+1. 
По данному целому числу 1≤n≤10^5 определите минимальное число операций k, 
необходимое, чтобы получить n из 1. 
Выведите k и последовательность промежуточных чисел.

Sample Input 1:
1
Sample Output 1:
0
1 

Sample Input 2:
5
Sample Output 2:
3
1 2 4 5 

Sample Input 3:
96234
Sample Output 3:
14
1 3 9 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234 


Мое решение:

#include 
#include 

using namespace std;

int main(int argc, const char * argv[]) {
    int n;
    cin >> n;

    int i = 1;
    vector m;
    m.push_back(i);
    while (i != n) {
        if (i * 3 <= n) {
            i *= 3;
        } else if (i * 2 <= n) {
            i *= 2;
        } else {
            i++;
        }
        m.push_back(i);
    }

    cout << m.size() - 1 << endl;
    for (int i = 0; i < m.size(); i++) cout << m[i] << " ";

    return 0;
}

    


Ответы

Ответ 1



Напишу свое решение, которое, по-моему, намного проще понять, чем уже опубликованные (я, например, не понимаю, почему они правильные). Алгоритм такой: заводим список, в котором в i-ой позиции будем хранить минимально число шагов, известное на данный момент, за которое можно попасть в N. В начале на будет известно только то, что в N-ой позиции стоит 0. Затем начинаем бежать по списк из конца в начало. На каждом шаге проверяем, из каких позиций мы можем попасть в текущую, и для этих позиций обновляем расстояние, если оно лучше, чем уже посчитанное ранее. К моменту когда мы прийдем в i-ый элемент, там будет записано минимальное расстояние, т.к. мы перебрали все варианты. Код такой: #include #include #include int main() { int N; std::cin >> N; std::vector steps(N + 1, INT_MAX); steps[N] = 0; std::vector next_num(N + 1, -1); for (int i = N; i > 1; --i) { int s = steps[i] + 1; // 3 * x if (!(i % 3) && steps[i / 3] > s) { steps[i / 3] = s; next_num[i / 3] = i; } // 2 * x if (!(i % 2) && steps[i / 2] > s) { steps[i / 2] = s; next_num[i / 2] = i; } // x + 1 if (steps[i - 1] > s) { steps[i - 1] = s; next_num[i - 1] = i; } } std::cout << steps[1] << std::endl; for (int i = 1; i != -1; i = next_num[i]) std::cout << i << ' '; std::cout << std::endl; } Сложность алгоритма -- линейная. Результаты на тестах: http://ideone.com/cuHyDP stdin 1  stdout 0 1 http://ideone.com/Ttku2H stdin 5  stdout 3 1 3 4 5 http://ideone.com/G5yg1I  stdin 96234  stdout 14 1 3 9 10 11 33 99 297 891 2673 8019 16038 16039 48117 96234

Ответ 2



У меня получилась другая последовательность чисел, но количество операций 14: long num = 96234; long x = num; int k = 0; while(x > 1) { if (x % 3 == 0) { x = x / 3; k++; } else if (x % 2 == 0) { if ((x - 1) % 3 == 0 && x % 4 != 0) { x--; k++; continue; } x = x / 2; k++; } else { x--; k++; } } Последовательность чисел: 1 2 6 7 21 22 66 198 594 1782 5346 16038 16039 32078 96234

Ответ 3



Итерационный алгоритм. Название говорит само за себя, алгоритм пытается перебрать все возможные варианты. По этой причине может работать долго. Для ускорения работы глубина рекурсии ограничена числом, выдаваемым алгоритмом Елены Обломовой #include #include #include using namespace std; int *VAR[100]; int LENS[100]; int IM[100]; int MAX_ITER; int probe(int i,int iter) { iter++; if(iter>MAX_ITER) return 10000; int j[3]; int ret[3]; int m; if(i<=1) return 0; ret[0]=ret[1]=ret[2]=10000; j[2]=i-1; ret[2]=probe(j[2],iter); if(i%2==0) {j[1]=i/2; ret[1]=probe(j[1],iter);} if(i%3==0) {j[0]=i/3; ret[0]=probe(j[0],iter);} if(ret[0]=10000) return ret[m]+1; if(m) ret[m]=probe(j[m],iter); IM[iter-1]=j[m]; ret[m]++; return ret[m]; } int ElenaOblomovaAlg(int num) { int x=num; int k=0; while(x > 1) { if (x % 3 == 0) { x=x/3; k++; } else if (x % 2 == 0) { if((x-1)%3==0 && x%4 != 0) { x--; k++; continue; } x=x/2; k++; } else { x--; k++; } } return k; } int main(int argc, const char * argv[]) { int n,i; int o,j=0; memset(VAR,0,sizeof(int *)*100); memset(LENS,0,sizeof(int)*100); cin >> n; MAX_ITER=ElenaOblomovaAlg(n)+1; cout << "ElenaOblomova algorithm return " << MAX_ITER-1 << "\n"; i=probe(n,0); if(i>1000) { i=MAX_ITER; cout << "Error recursion alg !!!\n"; } cout << "\ncount=" << i << "\n"; i--; for (; i>=0; i--) cout << IM[i] << " "; cout << n; return 0; } Дает всегда оптимальное разложение, но его самого есть куда оптимизировать. Например разложение числа 99997 полным перебором требует порядка 1.6 миллиарда тестов.

Ответ 4



По вашему алгоритму так и будет.. все правильно получается...Большая портянка чисел. Но на самом деле алгоритм другой должен быть: В обратную сторону - берем исходное число. Делим на 3. Если есть остаток - не учитываем а вместо этого делим на 2, если остаток опять будет от деления, значит вычитаем 1..... повторяем. пока не дойдем до 1.

Ответ 5



Правильное направление - это динамическое программирование и алгоритм Дейкстры. Надо просто завести массив на 105 элементов и по порядку, начиная с единицы, заполнит его минимально возможным количеством операций калькулятора (массив $steps). Наличие операции инкремента в калькуляторе даёт гарантию, что это возможно. Кроме того, для каждого из чисел запоминаются также предыдущие числа (от одного д трёх), соответствующие одному шагу оптимального решения (массив $previous). Это позволяет полностью избавиться от перебора (с момента заполнения массивов сложность алгоритма равна количеству операций калькулятора). В итоге удаётся: Определить минимальное количество операций калькулятора по пути к каждому числу. Найти число, требующее больше всего операций (77759 - 24 операции). Двигаясь по нулевым элементам массива previous, моментально получить один из оптимальных путей. Рекурсивным обходом массива previous максимально быстро определить все оптимальные способы, которыми можно получить данное число (на примере числа 96234). Программа (на PHP): function pre($i, $chain){ global $previous; if($i==0){ print("
"); foreach($chain as $val) print(" $val"); return; } array_push($chain, $i); $cnt = count($previous[$i]); if(!$i) return; for($c=0; $c < $cnt; $c++){ pre($previous[$i][$c], $chain); } } $n = 96234; $lim = 100000; $steps = array(); $steps[1] = 0; $previous[1]=array(0); $max = 0; for($i=2; $i<=$lim; $i++){ $i1=$i-1; $steps[$i] = $steps[$i1]+1; $previous[$i] = array($i1); $i2 = $i>>1; if(2*$i2 == $i){ if ($steps[$i2] < $steps[$i]-1){ $steps[$i] = $steps[$i2]+1; $previous[$i] = array($i2); }elseif($steps[$i2] == $steps[$i]-1){ array_push($previous[$i], $i2); } } $i3 = (int)($i/3); if(3*$i3 == $i) { if ($steps[$i3] < $steps[$i]-1){ $steps[$i] = $steps[$i3]+1; $previous[$i] = array($i3); }elseif($steps[$i3] == $steps[$i]-1){ array_push($previous[$i], $i3); } } if($steps[$i]>$max) $max = $steps[$i]; } asort($steps); var_dump(array_slice($steps, 99990, 99999, true)); printf("
steps[%d] = %d:   ", $pr=77759, $steps[$pr]); while($pr>1) printf(" %d", $pr=$previous[$pr][0]); print("
"); printf("
steps[%d] = %d:   ", $pr=99977, $steps[$pr]); while($pr>1) printf(" %d", $pr=$previous[$pr][0]); print("
"); printf("
steps[%d] = %d:   ", $pr=96234, $steps[$pr]); while($pr>1) printf(" %d", $pr=$previous[$pr][0]); print("
"); $chain = array(); pre($n, $chain); Результаты: array (size=10) 86399 => int 22 51407 => int 22 69119 => int 22 60911 => int 22 93311 => int 23 77758 => int 23 77757 => int 23 77755 => int 23 51839 => int 23 77759 => int 24 steps[77759] = 24:   77758 38879 38878 19439 19438 9719 9718 4859 4858 2429 242 1214 607 606 303 101 100 99 33 11 10 9 3 1 steps[99977] = 19:   99976 49988 24994 24993 8331 2777 2776 1388 694 693 231 77 76 38 19 18 9 3 1 steps[96234] = 14:   48117 16039 16038 8019 2673 891 297 99 33 11 10 9 3 1 96234 48117 16039 16038 8019 2673 891 297 99 33 11 10 9 3 1 96234 48117 16039 16038 5346 2673 891 297 99 33 11 10 9 3 1 96234 48117 16039 16038 5346 1782 891 297 99 33 11 10 9 3 1 96234 48117 16039 16038 5346 1782 594 297 99 33 11 10 9 3 1 96234 48117 16039 16038 5346 1782 594 198 99 33 11 10 9 3 1 96234 48117 16039 16038 5346 1782 594 198 66 33 11 10 9 3 1 96234 48117 16039 16038 5346 1782 594 198 66 22 21 7 6 3 1 96234 48117 16039 16038 5346 1782 594 198 66 22 21 7 6 2 1 96234 48117 16039 16038 5346 1782 594 198 66 22 21 7 6 2 1 96234 48117 16039 16038 5346 1782 594 198 66 22 11 10 9 3 1 96234 32078 16039 16038 8019 2673 891 297 99 33 11 10 9 3 1 96234 32078 16039 16038 5346 2673 891 297 99 33 11 10 9 3 1 96234 32078 16039 16038 5346 1782 891 297 99 33 11 10 9 3 1 96234 32078 16039 16038 5346 1782 594 297 99 33 11 10 9 3 1 96234 32078 16039 16038 5346 1782 594 198 99 33 11 10 9 3 1 96234 32078 16039 16038 5346 1782 594 198 66 33 11 10 9 3 1 96234 32078 16039 16038 5346 1782 594 198 66 22 21 7 6 3 1 96234 32078 16039 16038 5346 1782 594 198 66 22 21 7 6 2 1 96234 32078 16039 16038 5346 1782 594 198 66 22 21 7 6 2 1 96234 32078 16039 16038 5346 1782 594 198 66 22 11 10 9 3 1 Суммарное время выполнения ~ 1 секунды.

верстка 6-угольников




Подскажите, кто знает как это сверстать? В интернете мало инфы по этому поводу. Спасибо)
    


Ответы

Ответ 1



Для гексагонов есть генератор — http://csshexagon.com/ К коду, который он генерирует, надо добавлять *, *:before, *:after { -moz-box-sizing: border-box; box-sizing: border-box; } Иначе псевдоэлементы будут уезжать. Пример на основе кода из генератора: *, *:before, *:after { -moz-box-sizing: border-box; box-sizing: border-box; } .hexagon { position: relative; width: 300px; height: 173.21px; background-color: #e947bc; margin: 86.60px 0; border-left: solid 10px #640222; border-right: solid 10px #640222; transition: background-color 500ms; } .hexagon:before, .hexagon:after { content: ""; position: absolute; z-index: 1; width: 212.13px; height: 212.13px; -webkit-transform: scaleY(0.5774) rotate(-45deg); -ms-transform: scaleY(0.5774) rotate(-45deg); transform: scaleY(0.5774) rotate(-45deg); background-color: #e947bc; left: 33.9340px; transition: background-color 500ms; } .hexagon:before { top: -106.0660px; border-top: solid 14.1421px #640222; border-right: solid 14.1421px #640222; } .hexagon:after { bottom: -106.0660px; border-bottom: solid 14.1421px #640222; border-left: solid 14.1421px #640222; } .hexagon:hover, .hexagon:hover:before, .hexagon:hover:after { background-color: #fff; } .icon { position: absolute; width: 20px; height: 20px; top: 50%; left: 50%; margin-left: -10px; margin-top: -10px; background-color: #000; z-index: 10; }
Фиддл https://jsfiddle.net/mz2jmsdx/21/ Иконка внутри гексагона условно показана в виде чёрного квадрата, можно заполнить чем угодно и заложить для неё любые размеры.

Ответ 2



Полигоны можно создать с помощью SVG, указывая points по оси X & Y от 1 до 6. Update 1.0: Добавил иконки, но есть один нюанс. Тег не действителен в SVG, поэтому я использовал иконки таким образом: ðс1; Затем добавил font-family: svg text { font-family: FontAwesome; } Update 1.1: Добавил анимацию вращения иконок:) * { margin: 0; padding: 0; user-select: none; } .wrapper { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; } svg text { font-family: FontAwesome; font-size: 1.5rem; fill: #ffffff; pointer-events: none; transition: all .4s; } .hex { fill: #FC635E; stroke: #FE8682; stroke-width: 2px; transition: all .4s; } .hex:hover { fill: #fff; stroke: #FC635E; } .hex:hover+g text { fill: #FC635E; transform: rotate(360deg) scale(0.9); }
Update 1.2: Добавил решение на HTML+CSS: * { margin: 0; padding: 0; } body { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; } i { position: absolute; left: 50%; top: 50%; color: white; transform: translate(-50%, -50%); z-index: 2; } .hexagon, .hexagon::before, .hexagon::after, .fill, .fill::before, .fill::after, i { transition: 0.3s; } .hexagon, .hexagon::before, .hexagon::after { background-color: #FE8682; } .fill, .fill::before, .fill::after { background-color: #FC635E; } .hexagon::before, .hexagon::after { transform: translateX(-50%) scaleY(0.7) rotate(45deg); } .hexagon { position: relative; margin: 3rem; width: 7.7rem; height: 4rem; font-size: 2rem; } .hexagon::before, .hexagon::after { content: ""; position: absolute; width: 5.4rem; height: 5.4rem; } .hexagon::before { top: -2.7rem; left: 50%; } .hexagon::after { bottom: -2.7rem; left: 50%; } .hexagon:hover { background-color: #FC635E } .hexagon:hover i { color: #FC635E; } .hexagon:hover::after { background-color: #FC635E } .hexagon:hover::before { background-color: #FC635E } .hexagon:hover .fill { background-color: white; } .hexagon:hover .fill::after { background-color: white; } .hexagon:hover .fill::before { background-color: white; } .fill { position: absolute; left: 50%; top: 50%; width: 7rem; height: 3.5rem; z-index: 1; transform: translate(-50%, -50%); } .fill::before, .fill::after { content: ""; position: absolute; width: 5rem; height: 5rem; transform: scaleY(0.7) rotate(45deg); } .fill::before { top: -2.5rem; left: 1rem; } .fill::after { bottom: -2.5rem; left: 1rem; }


Ответ 3



Генератор кривоугольников. Скрипт генерирует не только шестиугольники но и многогранники с любым количество вершин. Вариант с равными гранями есть много где, поэтому в этом примере равные грани мы немного подправим, что бы фигуры стали более индивидуальными. В данном примере мы делаем 4,5,6 и 7 угольники. var svgNS = "http://www.w3.org/2000/svg"; var points; for (var i = 0; i <= 3; i++) { points = MakeIdealMnogogrannik(30, 4 + i); for (var j = 1; j <= 3; j++) { document.getElementById(`svg${i}${j}g`).appendChild(MakeRandomMnogogrannik(7)); } } function MakeIdealMnogogrannik(rad, n) { var angle = 2 * Math.PI / n; var points = []; for (var i = 0; i < n; i++) { points.push({ x: rad * Math.sin(angle * i), y: -rad * Math.cos(angle * i) }); } return points; } function MakeRandomMnogogrannik(distance) { var path = document.createElementNS(svgNS, "path"); var points1 = new Array(points.length); for (var i = 0; i < points.length; i++) { points1[i] = { x: points[i].x + randomMax(distance), y: points[i].y + randomMax(distance) } } var d = `M ${points1[0].x} ${points1[0].y}`; for (var i = 1; i < points.length; i++) { d += ` L ${points1[i].x} ${points1[i].y}`; } d += " Z"; // path.classList.add("hex"); var rot = randomMax(360); path.setAttribute("d", d); return path; } function randomMax(max) { return Math.floor(Math.random() * (max + 1)); } body { display: flex; flex-direction: column; } .line { display: flex; justify-content: space-around; } .hex { fill: #FC635E; stroke: #FE8682; stroke-width: 2px; transition: all .4s; } .hex:hover { fill: #fff; stroke: #FC635E; } svg text { font-family: FontAwesome; font-size: 1.35rem; fill: #ffffff; pointer-events: none; transition: all .4s; } .hex:hover+g text { fill: #FC635E; color: red; }
Стили и часть разметки взяты из ответа St1myL.

Ответ 4



SVG конечно хорошо но если можно избежать других технологий то я стараюсь не применять ни чего кроме html и css.... надеюсь мой ответ помог понять * { margin: 0; padding: 0; } .item { width: 150px; height: 60px; background: red; margin: 100px auto; position: relative; } .item:after { content: ""; display: block; width: 150px; height: 60px; background: red; position: ; transform: rotate(45deg); } .item:before { content: ""; display: block; width: 150px; height: 60px; background: red; position: ; transform: rotate(-45deg); position: absolute; } .outer { width: 65px; height: 147px; background: red; position: absolute; left: 28%; top: -71%; margin-left: -0%; border-radius: 4px; z-index: 100; line-height: 140px; text-align: center; }
иконка


Линия до и после текста над картинкой


Я хочу создать линию до и после центрированного заголовка. Линия и текст должны имет
прозрачный фон, чтобы иметь возможность позиционировать их на неодинаковом фоне. Строка не должна быть больше 100% ширины.     

Как здесь на картинке:  

    

Текст заголовка может измениться:  


Ширина заголовка неизвестна   
Заголовок может занимать несколько строк  


    

h1 {
  text-align: center;
  border-bottom: 1px solid #000;
}         


 

Today

Перевод вопроса: Line before and after title over image @JUO


Ответы

Ответ 1



Нестандартное решение )) : fieldset { border-left: none; border-right: none; border-bottom: none; text-align: center; }
Lorem ipsum.
Более стандартное: header { text-align: center; overflow: hidden; } h1 { display: inline-block; position: relative; } h1:before, h1:after { content: ''; position: absolute; top: 50%; height: 1px; background: #000; } h1:before { right: 100%; left: -1000%; } h1:after { left: 100%; right: -1000%; }

Lorem ipsum.

ex , ex

Ответ 2



Вы можете сделать линию по обеим сторонам заголовка с 2 псевдоэлементами и границами: Это работает на transparent background (линии и название имеют прозрачные фоны). Длина линии адаптируется к ширине заголовка, поэтому они всегда начинаются и заканчиваются с одинаковыми пробелами независимо от длины заголовка. Заголовок может занимать несколько строк, в то время как левая и правая линии остаются вертикально центрированными (обратите внимание, что вам нужно обернуть заголовок тегом span, чтобы это работало. @import url(http://fonts.googleapis.com/css?family=Open+Sans:300); body { background-image: url(http://i.imgur.com/EzOh4DX.jpg); background-repeat: no-repeat; background-size: 100% auto; font-family: 'Open Sans', sans-serif; } h1 { width: 70%; margin: .7em auto; overflow: hidden; text-align: center; font-weight:300; color: #fff; } h1:before, h1:after { content: ""; display: inline-block; width: 50%; margin: 0 .5em 0 -55%; vertical-align: middle; border-bottom: 1px solid; } h1:after { margin: 0 -55% 0 .5em; } span { display: inline-block; vertical-align: middle; }

Today

Today news

Today
news

Перевод ответа: Line before and after title over image @web-tiki

Ответ 3



Вот еще один подход, используя дисплей flexbox. Свойство flex-grow определяет, ка свободное пространство должно распределяться между элементами, когда их общий размер меньше размера контейнера. По умолчанию для элементов, описывающие строки, width не указана, и у них нет содержимог (то есть они в основном пусты и не занимают места). Однако применение flex-grow н этих элементах обеспечивала бы равномерное распределение между ними оставшегося пространства (общее пространство контейнера - пространство текста). Это заставляет линию выглядеть так, как будто она проходит от начала до конца за исключением того места, где находится текст. Сплошная линия по обе стороны контента: В приведенном ниже фрагменте, градиент сверху вниз используется для создания эффекта сплошной линии с обеих сторон контента. h3{ display: flex; flex: 1; width: 70%; margin: 20px auto; line-height: 1em; } .heading:before, .heading:after, .heading-ie span.after, .heading-ie span.before{ content: ''; flex-grow: 1; margin: 0px 4px; background: linear-gradient(to right, white, white); background-size: 100% 2px; background-position: 0% 50%; background-repeat: repeat-x; } /* Just for demo*/ body{ background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%); }

Something broader

Something broader and broader

Something broader
and spans multiple
no. of lines

Something broader and broader and broader

Линия с градиентным эффектом с обеих сторон контента: В приведенном ниже фрагменте, тонкий градиент слева направо используется для создани эффекта линии, которая идет от сплошного цвета рядом с текстом к прозрачному с другой стороны. h3{ display: flex; flex: 1; width: 70%; margin: 20px auto; line-height: 1em; } .heading:before, .heading:after, .heading-ie span.after, .heading-ie span.before{ content: ''; flex-grow: 1; margin: 0px 4px; background-size: 100% 2px; background-position: 0% 50%; background-repeat: repeat-x; } .heading:before, .heading-ie span.before{ background-image: linear-gradient(to right, transparent, white); } .heading:after, .heading-ie span.after{ background-image: linear-gradient(to left, transparent, white); } /* Just for demo*/ body{ background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%); }

Something broader

Something broader and broader

Something broader
and spans multiple
no. of lines

Something broader and broader and broader

Примечание. В фрагменте я использовал дополнительные элементы span для строк, потом что IE11, по-видимому, не поддерживает flex-grow для псевдоэлементов. В противном случае то же самое может быть достигнуто и с псевдоэлементом. Недостатком этого подхода является довольно низкая поддержка браузерами этой функции. Вам также может потребоваться адаптировать некоторые настройки браузера, которы подробно описаны в моем ответе здесь, который подобен этому. В настоящее время это не дает ничего сверх ответа @web-tiki, но является еще одни возможным вариантом. Такой подход был бы более полезным в случаях, подобных приведенным ниже: h3{ display: flex; flex: 1; width: 70%; margin: 20px auto; line-height: 1em; } .heading-ie .start, .heading-ie .middle, .heading-ie .end{ content: ''; flex-grow: 1; margin: 0px 4px; background: linear-gradient(to right, white, white); background-position: 0% 50%; background-size: 100% 2px; background-repeat: repeat-x; } /* Order specifies the order in which the elements should be presen within container */ .content-1{ order: 2; } .start{ order: 1; } .middle{ order: 3; } .content-2{ order: 4; } .end{ order: 5; } /* Just for demo*/ body { background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%); }

Text here and here too

Text with
line break
and here with
line break too

Источник

Книги и учебные ресурсы по PHP


Рекомендуемая литература, курсы и документация по PHP.


Не создавайте новых ответов — редактируйте общий ответ.
Не размещайте ссылки на нелегальный контент, вроде торрент-трекеров.
Старайтесь сохранять разделение по категориям.





  Данный перечень входит в поддерживаемый сообществом Сборник учебных ресурсов по программированию.

    


Ответы

Ответ 1



Официальная документация PHP.NET - Руководство по PHP Литература Для начинающих PHP 7. Дмитрий Котеров, Игорь Симдянов. Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript, CSS и HTML5. Робин Никсон. PHP. Создание динамических страниц. Дэвид Пауэрс. PHP: Правильный путь. (PHP: The right way) - Онлайн книга. Для среднего уровня PHP 5. Полное руководство. Джон Коггзолл PHP. Объекты, шаблоны и методики программирования. Мэт Зандстра. Самоучитель PHP 7. Максим Кузнецов, Игорь Симдянов. Для продвинутого уровня Domain-Driven Design in PHP. Carlos Buenosvinos, Christian Soronellas, Keyvan Akbary Полезные ссылки Список всего, связанного с PHP PhpTheRightWay - список актуальных инструментов/библиотек/подходов