Страницы

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

четверг, 2 апреля 2020 г.

Где использовать volatile

#java #многопоточность #concurrency

                    

Когда можно использовать volatile, если он не обеспечивает атомарность чтения и записи
как Atomic'и.
Мне не понятно в чем разница между volatile и synchronized, если и то и другое обеспечивает
синхронизацию между кэшами ядер процессора.

    


Ответы

Ответ 1



Модификатор volatile гарантирует видимость операций с полем и сохранение их последовательности. Волатильную переменную можно, например, использовать как флаг завершения работы потока: public class Main { private static volatile boolean run = true; public static void main(String[] args) throws Exception { new Thread(() -> { long x = 0; while (run) { System.out.println(++x); try { Thread.sleep(1000); } catch (InterruptedException exc) {} } }).start(); Scanner scanner = new Scanner(System.in); while (run) { String line = scanner.nextLine(); if ("exit".equals(line)) run = false; } } } Без модификатора volatile у вас нет гарантии, что поток выводящий значения переменной x когда-нибудь заметит, что главный поток изменил состояние переменной run. Синхронизация гарантирует видимость операций, сохранение их последовательности и атомарность. public class Main { private static int x = 0; private static int y = 1000; private static synchronized void transfer() { ++x; --y; } public static void main(String[] args) throws Exception { for (int a = 0; a < 10; a++) { new Thread(() -> { for (int b = 0; b < 100; b++) { transfer(); } }).start(); } System.out.println(x); System.out.println(y); } } Без модификатора synchronized у вас нет гарантии, что значение переменной x будет увеличено на столько же, на сколько уменьшено значение переменной y, так как порядок и продолжительность выполнения потоков непредсказуемы. Во втором примере volatile не поможет. В первом может помочь использование синхронизации, но тогда на каждой итерации один из потоков будет блокировать мьютекс, а второй потом будет останавливаться, пока мьютекс не будет освобождён. Это существенно медленнее проверки состояния волатильной переменной.

Ответ 2



Вам почти правильно ответили. Только оптимизации несколько другого рода. Дело в том, что переменная может быть закеширована для более быстрого доступа. Вариантов куча где именно. Например она может быть закеширована для каждого процессора отдельно, может быть закеширована в потоке, в принципе это зависит от того, какая реализация JVM используется. Volatile просто запрещает подобное кэширование. Теперь как его использовать. Volatile работает быстрее, потому что никаких блокировок не происходит. В этом его преимущество перед synchronized. Работа со ссылками атомарна, поэтому там в теории это может быть актуальным. А так да, конструкция относительно редкая, обычно при многопоточности используется что-то специфическое, дабы упростить работу с ней. UPD. Там "на заборах" пишут, что long и double которые не обязательно атомарные, становятся атомарными с volatile. Но официального подтверждения я этому не нашел, если у кого то есть точная информация по этому поводу, будет круто

Git требует пароль при каждом push

#git #github

                    
Все работало верно, но после несколько хаотичных экспериментов git стал просить логин
пароль при каждом push и в IDE и в терминале. Помогите пожалуйста это исправить назад.
Но ssh ключи я кажется не трогал. 

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/triodjangopiter/account-manager
  Push  URL: https://github.com/triodjangopiter/account-manager
  HEAD branch: master
  Remote branches:
    feature/custom_filter tracked
    feature/toolbar       tracked
    master                tracked
  Local branches configured for 'git pull':
    feature/custom_filter merges with remote feature/custom_filter
    feature/toolbar       merges with remote feature/toolbar
    master                merges with remote master
  Local refs configured for 'git push':
    feature/custom_filter pushes to feature/custom_filter (up to date)
    feature/toolbar       pushes to feature/toolbar       (up to date)
    master                pushes to master                (up to date)

    


Ответы

Ответ 1



Это довольно частая ошибка. origin нужно заменить на ssh ссылку: git remote set-url origin git@github.com:triodjangopiter/account-manager.git

WPF: замостить контейнер элементами

#c_sharp #wpf

                    
Здравствуйте, сделал элемент UserControl, который может иметь разные высоту и ширину.
 Необходимо создать алгоритм который будет при добавлении этого элемента в ScrollViewer(или
другой элемент) располагать его в месте наиболее подходящем для него, т. е., например,
вот тут:



было бы правильно, если бы "серый" элемент был между синим и зелёным. Ширина ScrollViewer
фиксированная.
    


Ответы

Ответ 1



У вас размещение элементов - часть бизнес-логики, поэтому алгоритм поместим в VM. Я написал такой простой класс, представляющий ящик: class BoxVm : Vm { public int Width { get; } public int Height { get; } public BoxVm(int width, int height) { Width = width; Height = height; } } И класс, представляющий размещение ящика: class PlaceVm : Vm { public int X { get; } public int Y { get; } public BoxVm Box { get; } public PlaceVm(int x, int y, BoxVm box) { X = x; Y = y; Box = box; } public bool IsIntersects(PlaceVm place) { return !(X >= place.X + place.Box.Width || X + Box.Width <= place.X || Y >= place.Y + place.Box.Height || Y + Box.Height <= place.Y); } } Также в нем есть метод для определения пересекаются ли 2 размещения. Теперь класс, представляющий склад: class StorageVm : Vm { public int Width { get; } public int Height { get; } public StorageVm(int width, int height) { Width = width; Height = height; Places = new ObservableCollection(); } public ObservableCollection Places { get; } public PlaceVm AddBox(BoxVm box) { for (int y = 0; y <= Height - box.Height; ++y) for (int x = 0; x <= Width - box.Width; ++x) { var place = new PlaceVm(x, y, box); if (!Places.Any(p => p.IsIntersects(place))) { Places.Add(place); return place; } } throw new InvalidOperationException("Невозможно разместить!"); } } Надеюсь, здесь вам всё понятно. Если у вас сетка не ограничена снизу, то просто замените цикл for по y на цикл while, ну и проверку, влазит ли элемент по ширине, надо будет вынести перед циклом и бросать исключение в ней, а не как у меня в конце. Теперь главная VM: class MainVm : Vm { int width; public int Width { get => width; set => Set(ref width, value); } int height; public int Height { get => height; set => Set(ref height, value); } public StorageVm Storage { get; } public ICommand AddCommand { get; } public MainVm() { Storage = new StorageVm(10, 10); AddCommand = new DelegateCommand(_ => Storage.AddBox(new BoxVm(Width, Height))); } } Здесь тоже всё просто - один склад и одна команда для добавления ящика на склад. Теперь GUI. Нам потребуется конвертер из ячеек в экранные размеры, он очень простой: class ScaleConverter : IValueConverter { public int Coeff { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (int)value * Coeff; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } Он просто умножает входное значение на коэффициент. Теперь разметка:

Скрытие элемента при клике вне него

#javascript #jquery

                    
Данный код скрывает элемент .header__bottom-hover-menu, при клике вне него.



$(function() {

  $('.header__nav-item').click(function() {
    if (window.innerWidth > 1150) {
      let overlay = $('.overlay');

      $('.header__bottom-hover-menu.active, .header__top, .header__bottom').removeClass('active');
      $('.header__nav-item > a.active').removeClass('active');
      overlay.removeClass('active');

      if ($(this).find('.header__bottom-hover-menu').length > 0) {
        $('a.submenu').addClass('active');
        $('.header__top, .header__bottom').addClass('active');
        overlay.addClass('active');
      }
    }
  }, function() {
    if (window.innerWidth > 1150) {
      $('.header__bottom-hover-menu.active, .header__top, .header__bottom').removeClass('active');
      $('.overlay').removeClass('active');
      $('.header__nav-item > a.active').removeClass('active');

      $('.header__hover-list-item.active').removeClass('active');
      $('.header__hover-tab.active').removeClass('active');

      $(this).find('.header__bottom-hover-menu').addClass('active');
      $('.header__hover-list-item[data-tab="1"]').addClass('active');
      $('.header__hover-tab[data-tab="1"]').addClass('active');
    }
    return false
  });
  $(document).on('click', function(e) {
    var myDiv = $(".header__bottom-hover-menu");
    if (!myDiv.is(e.target) && myDiv.has(e.target).length === 0) {
      $('.header__bottom-hover-menu').hide();
    }
  })
});




но этот элемент ранее сам появлялся при клике на пункт меню, и теперь, после того
как он пропал, обратно он не появляется при клике на пункт меню.

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


Ответы

Ответ 1



Вам нужно выполнить следующий код, чтобы элемент опять появился $('.header__bottom-hover-menu').show(); При обработчике клика можно контролировать когда элемент должен появится, а когда исчезать.

Динамическое добавление вложенных переменных в существующую структуру переменных

#ansible

                    
Есть структура вида в котором хранятся объекты со своими какими-то свойствами, которые
прописаны в файле определения переменных:

vars:
  objects:
    - name: objectA:
      sectionB:
        property1: "value1"
        property2: "value2"
        property3: "value3"


Хотел бы динамически во время исполнения моего playbook исполнять task, который добавлял
бы в данный(ые) объект(ы) дополнительное динамически вычисляемое свойство.

Нашел много примеров, которые динамически добавляют элементы (items) в словарь (dictionary),
но вот подобного найти не получается.

Требуется сделать нечто подобное (один из вариантов, которые я пробовал использовать):

- set_fact:
    item.sectionB: "{{item.sectionB | combine(property_string) }}"
  with_items:
    - "{{ objects }}"
  vars:
    property_string: '{ property4: "value4" }'


Чтобы получить в итоге:

vars:
  objects:
    - name: objectA:
      sectionB:
        property1: value1
        property2: value2
        property3: value3
        property4: value4


Пробовал использовать функцию combine(), она в таком виде отрабатывает без ошибок,
но структуру не изменяет, а функция union() завершается ошибкой.
    


Ответы

Ответ 1



Вот здесь описан принцип решения: https://ansibledaily.com/process-complex-variables-with-set_fact-and-with_items/ Изменить изначальную переменную нельзя, но можно при помощи set_fact сделать факт с таким же именем, который в большинстве случаев будет меть приоритет к изначальной переменной. Первым шагом формируете новый список объектов с добавлением к элементам нужных атрибутов через combine. Примерно: - set_fact: tmp_object: "{{ item | combine(<объет_с_дополнениям>) }}" with_items: "{{ objects }}" register: tmp_objects И потом из tmp_objects достаем то, что нам на самом деле нужно: - set_fact: objects: {{ tmp_objects.results | map(attribute='ansible_facts.tmp_object') | list }}"

Странные полоски в паттерне

#svg

                    
Пробую сделать такой pattern, и непонятно откуда появляются вертикальные полоски,
которых быть не должно.

При этом сам элемент pattern'a если вывести (смотрите пример) никаких полосок нет.



body {
  margin: 0;
  background: black;
}

.c1 {
  fill: #ffd77a;
  stroke: #ffd77a;
}

.c2 {
  fill: #ffed7a;
  stroke: #ffed7a;
}

.c3 {
  fill: #fbff7a;
  stroke: #fbff7a;
}

.c4 {
  fill: #e4ff7a;
  stroke: #e4ff7a;
}

.c5 {
  fill: #ceff7a;
  stroke: #ceff7a;
}

.c6 {
  fill: #b8ff7a;
  stroke: #b8ff7a;
}

.c7 {
  fill: #a2ff7a;
  stroke: #a2ff7a;
}

    
        
            
            
        
        
            
            
            
            
        

        
            
            
            
            
        
    

    

    





Прилагаю скриншот на случай если это глюк моего рендера (Yandex Browser)



А вот если размер паттерна сделать другой то всё работает нормально



body {
  background: black;
  margin: 0;
}

.c1 {
  fill: #ffd77a;
  stroke: #ffd77a; }

.c2 {
  fill: #ffed7a;
  stroke: #ffed7a; }

.c3 {
  fill: #fbff7a;
  stroke: #fbff7a; }

.c4 {
  fill: #e4ff7a;
  stroke: #e4ff7a; }

.c5 {
  fill: #ceff7a;
  stroke: #ceff7a; }

.c6 {
  fill: #b8ff7a;
  stroke: #b8ff7a; }

.c7 {
  fill: #a2ff7a;
  stroke: #a2ff7a; }

    
        
            
            
        
        
            
            
            
            
        

        
            
            
            
            
        
    

    

    





Во втором примере размер pattern'a не 50, а 40.

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

Как поправить данный пример я методом проб и ошибок понял, можно сделать stroke-width:
5px; и артефакты пропадают. Но мне не понятна логика их появления. 

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


Ответы

Ответ 1



Проведя ряд тестов понял откуда берутся полосы. При размерах родительского элемента которые делятся нацело с размером паттерна - всё хорошо. Когда деление рождает дробные числа получаются зазоры. Смысл в том что у меня в примере есть параллельные линии между элементами el1 и big1, при кратных размерах они рисуются вплотную, при дробных размерах появляется зазор. Вероятно это связано с округлениями и особенностями алгоритма рисований кривых. В данном случае это надо понимать как данность и особенность рендера SVG, которую надо учитывать. Вот пример для тестов. Верхние квадраты сделаны с размерами символа кратными разерам внутри символа. Нижние квадраты - некратные размеры. Как можно видеть в нижних квадратах появляется зазор. Специально что бы его было лучше видно добавил белые полосы, на границе легко отслеживается смена чёрного и белого. Привожу скриншот как это выглядит у меня на случай если у кого-то другой рендер.

Обратная анимация, при удалении класса

#javascript #html #css

                    
Делаю анимированный менюбар. Анимацию на открытие сделал, а на закрытие обратную
анимацию не получается сделать. Подскажите, как это делается?



var collapse = document.getElementById('collapse-menu');
collapse.addEventListener('click', function(e) {
  this.classList.toggle('l-header__bar_close');
});
@keyframes barToClose_one {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, 9px);
  }
  100% {
    transform: translate(0, 9px) rotate(45deg);
  }
}

@keyframes barToClose_two {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, 0) rotate(-45deg);
  }
}

@keyframes barToClose_three {
  0% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(0, -9px);
  }
  100% {
    transform: translate(0, -9px) rotate(-45deg);
  }
}

.l-header {
  height: 45px;
  background-color: #10151c;
}

.l-header__bar {
  width: 50px;
  height: 100%;
  padding: 6px 10px;
  box-sizing: border-box;
}

.l-header__icon-bar {
  background-color: #fff;
  height: 3px;
  margin-top: 6px;
  border-radius: 2px;
}


/* Animate bar to close */

.l-header__bar_close .l-header__icon-bar:nth-child(1) {
  animation: barToClose_one 500ms cubic-bezier(0, .61, 1, .55) forwards;
}

.l-header__bar_close .l-header__icon-bar:nth-child(2) {
  animation: barToClose_two 500ms cubic-bezier(0, .61, 1, .55) forwards;
}

.l-header__bar_close .l-header__icon-bar:nth-child(3) {
  animation: barToClose_three 500ms cubic-bezier(0, .61, 1, .55) forwards;
}




    


Ответы

Ответ 1



Слишком с анимацией намудрили. Замените её на обычный transform, а его анимируйте через transition: var collapse = document.getElementById('collapse-menu'); collapse.addEventListener('click', function(e) { this.classList.toggle('active'); }); .l-header { height: 45px; background-color: #10151c; } .l-header__bar { width: 50px; height: 100%; padding: 17px 10px; box-sizing: border-box; } .l-header__icon-bar { background-color: #fff; height: 3px; border-radius: 2px; } /* Animate bar to close */ .l-header__icon-bar{ transition: transform .3s, opacity .3s; } .active .l-header__icon-bar:nth-child(1) { transform: translate(0, 3px) rotate(45deg); } .l-header__icon-bar:nth-child(1) { transform: translate(0, -6px) } .active .l-header__icon-bar:nth-child(2) { opacity: 0; } .active .l-header__icon-bar:nth-child(3) { transform: translate(0, -3px) rotate(-45deg) } .l-header__icon-bar:nth-child(3) { transform: translate(0, 6px) }

Ответ 2



на jQuery я знаю как это сделать не применял вашу разметку но аналогичная ... смотрите $(document).ready(function() { $(".trigger").click(function(e) { $(this).toggleClass("active_trigger"); }); }); *{ margin:0; padding:0; } span.trigger{ display:inline-block; width:50px; height:50px; margin:40px; } span.trigger i{ display:block; width:40px; height:10px; background:#000; margin:4px auto; transition:all .3s linear; } span.active_trigger i:nth-child(2){ opacity:0; } span.active_trigger i:nth-child(1){ transform:rotate(-45deg)translate(-12px,10px); } span.active_trigger i:nth-child(3){ transform:rotate(45deg)translate(-10px,-7px); }