Страницы

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

вторник, 29 января 2019 г.

Появление элемента после длительного нажатия на блок

Здравствуйте! Имеется список приложений, на мобильных устройствах предусмотрено появление кнопки при длительном нажатии любого из пунктов списка. До этого с версткой подобных элементов не сталкивался, прошу подсказать как такие вещи реализуются.


Ответ

$(document).ready(function(){ var shows = 0; $('#longClick').mousedown(function(){ shows = setTimeout(function(){ $('#shower').show(); }, 2000); }); $('#longClick').mouseup(function(){ clearTimeout(shows); }); $('*').not($('#shower')).mousedown(function(){ $('#shower').hide(); }); });

Click me 2 second
Click for close
Click for close

Анонимный интерфейс c#

Есть интерфейс
intefrace IMy { void say(String msg); }
Есть класс
class My { IMy iMy; public My() { iMy = (str) = > Console.WriteLine(str); //ошибка iMy.say("Text"); } }
На строке с //ошибка мне пишет
Cannot convert lambda expression to type IMy, because it is not a delegate type
Что мне надо изменить в коде, чтобы я мог инициализировать переменную iMy моим способом?
P.S. сам пишу на java, и там такая конструкция работает. Какая аналогичная конструкция в c#?


Ответ

Судя по примеру использования вместо интерфейса в данном случае можно использовать делегат Action, например так
class My { Action iMy; public My() { iMy = (str) => Console.WriteLine(str); //ок iMy("Text"); } }

Поиск в JSON строке значения

Мне нужно получить значение из динамичного JSON. Он огромен , поэтому приводить его полностью не имеет смысла. Меня интересует значения тиража, как мне туда добраться максимально изящно?
По логике мне надо найти слово Тираж в строке и перейти в соседнюю ячейку и получить значение.


Ответ

Воспользуйтесь готовыми парсерами. Читать JSON поиском или регулярными выражениями - не очень хорошая идея. Например, свойство Value не обязано идти до свойства Name, оно может идти и после него. Смысл JSON при этом не изменится, а отловить все такие случаи при поиске будет тяжело.
Json.NET поддерживает такую вещь, как запросы JSONPath
var json = @"{ ""Editions"": {}, ""ItemType"": 5, ""Capabilities"": { ""Capabilities"": [ { ""Name"": ""Тираж"", ""Value"": ""20000"", ""AdditionalProperties"": {} }, { ""Name"": ""aaaa"", ""Value"": ""bbb"", ""AdditionalProperties"": {} } ] } }";
var obj = JObject.Parse(json); var value = (string)obj.SelectToken("$.Capabilities.Capabilities[?(@.Name == 'Тираж')].Value");
Если JSON действительно огромный и десериализовать целиком его накладно по памяти, то придется воспользоваться JsonTextReader, десереализуя только небольшие части файла (код приблизительный, без проверок):
string value = null; using (var reader = new JsonTextReader(new StringReader(json))) { // читаем json, пока не придем в объект Capabilities while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName && (string)reader.Value == "Capabilities") { break; } }
reader.Read();
// каждый объект из массива десериализуем в JObject while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { var obj = JObject.Load(reader); if ((string)obj["Name"] == "Тираж") { value = (string)obj["Value"]; break; } } } }

Аналог функции Swap

Есть ли в С# аналог функции Delphi Swap() ? Верно ли я понимаю, что функция swap меняет местами 2 байта ?


Ответ

В комментариях подсказали, где подсмотреть готовое решение:
Для данных типа ushort:
private ushort Swap(ushort number) { var hi = (byte)(number >> 8); var lo = (byte)(number & 0xff); return (ushort)((lo << 8) | hi); }
Для данных типа Int:
int SwapInt(int number) { var hi = (byte)(number >> 24); var lo = (byte)(number & 0xff); return ((number & 0xffff00) | (lo << 24) | hi); }

Как узнать является ли тип перечислением?

Можно ли как-нибудь проверить, является ли тип перечислением, т.е. enum или enum class?


Ответ

#include #include
class A {}; enum E {}; enum class Ec : int {};
int main() { std::cout << std::boolalpha; std::cout << std::is_enum::value << '
'; std::cout << std::is_enum::value << '
'; std::cout << std::is_enum::value << '
'; std::cout << std::is_enum::value << '
'; }
Ну, или
std::cout << std::is_enum
() << '
'; std::cout << std::is_enum() << '
'; std::cout << std::is_enum() << '
'; std::cout << std::is_enum() << '
';

Ошибка сборки: Cannot find -lGL

При попытке сборки проекта Qt Widgets выдает вот такую ошибку:
g++ -Wl,-rpath,/home/keyreal/Qt/5.7/gcc_64/lib -o untitled3 main.o mainwindow.o moc_mainwindow.o -L/home/keyreal/Qt/5.7/gcc_64/lib -lQt5Widgets -L/usr/lib64 -lQt5Gui -lQt5Core -lGL -lpthread /usr/bin/ld: cannot find -lGL collect2: error: ld returned 1 exit status make: *** [untitled3] Ошибка 1 22:41:13: Процесс «/usr/bin/make» завершился с кодом 2. Ошибка при сборке/установке проекта untitled3 (комплект: Desktop Qt 5.7.0 GCC 64bit)`
Ошибку выдает только если создается проект Qt Widgets, с консольным приложением вроде всё работает. Проект создается пустой абсолютно, т.е. туда ничего не внесено и никаких дополнительных классов не используется
ОС - Ubuntu 14.04 с XFCE.


Ответ

Установите пакет libgl1-mesa-dev
Добавлено
Разумеется, нет возможности гарантировать, что на неких специфичных убунтах с нестандартным набором установленных пакетов, обозначенный пакет не затребует что-либо удалить. Речь о стандартной поставке Ubuntu с Gnome, начиная с 14.04 и по 16.04 включительно. Подозреваю, что и для более ранних версий, а также для версий с XFCE ситуация не изменится (самолично не проверял, не пользуюсь этим DE).
Предоставляемые пакетом файлы:
/. /usr /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/libGL.so /usr/lib/x86_64-linux-gnu/libglapi.so /usr/lib/x86_64-linux-gnu/mesa /usr/lib/x86_64-linux-gnu/mesa/libGL.so /usr/lib/x86_64-linux-gnu/pkgconfig /usr/lib/x86_64-linux-gnu/pkgconfig/gl.pc /usr/share /usr/share/bug /usr/share/bug/libgl1-mesa-dev /usr/share/bug/libgl1-mesa-dev/control /usr/share/bug/libgl1-mesa-dev/script /usr/share/doc /usr/share/doc/libgl1-mesa-dev /usr/share/doc/libgl1-mesa-dev/changelog.Debian.gz /usr/share/doc/libgl1-mesa-dev/copyright
Как видно, пакет содержит искомую библиотеку: libGL.so
При установке на систему Ubuntu 16.04 Gnome ничего не запрашивает снести.

Зачем нужны переменные таблицы и когда их лучше использовать?

В MS SQL есть переменные таблицы.
В некоторых случаях я замечал, что темповые таблицы работают быстрее, за счет того, что в них используется параллелизм в отличии от переменных.
Единственный минус темповых таблиц, как я думаю - это то, что их нужно проверять и дропать если они есть перед создание.
Так вот, для каких целей они могут понадобится, когда есть темповые таблицы и когда их лучше использовать?


Ответ

Единственный минус темповых таблиц, как я думаю - это то, что их нужно проверять и дропать если они есть перед созданием.
На мой взгляд это проблема только при @@nestlevel равном 0, да и то не всегда (например, если открываем соединение, создаём #-таблицу, что-то делаем и закрываем соединение, то в проверке нет необходимости). Внутри модуля (триггера или процедуры), если нужно создать #table, то можно не проверять и не дропать (это может быть и вредным), даже если на внешнем уровне уже была создана #table с тем же самым именем.
Т.е., например, есть процедура
create procedure SomeProc as begin set nocount on;
create table #table (id int); insert into #table values (1), (2);
select * from #table; end GO
Можно создать #table и вызвать SomeProc
create table #table (value float); insert into #table values (100.0), (200.0); exec SomeProc; -- #table внутри SomeProc - это другая #table select * from #table; drop table #table; GO
при этом #table, созданная снаружи SomeProc, и #table, созданная внутри SomeProc - разные и между собой не интерферируют. Если внутри SomeProc перед create table #table поставить проверку существования #table и drop table #table, то уничтожится таблица, созданная на внешнем уровне, и код, следующий за процедурой, сломается.
Так вот, для каких целей они могут понадобиться, когда есть темповые таблицы
При выборе между @table и #table, как мне кажется, следует исходить из свойств и особенностей этих двух типов таблиц. У @-таблиц по сравнению с #-таблицами довольно много ограничений, много общего, и есть особенности присущие только @-таблицам.
Подробно этот вопрос освещён здесь и здесь. Ниже некоторое обобщение информации по этим двум ссылкам (неполное).

Хранилище: Вопреки расхожему представлению о том, что @-таблицы хранятся в оперативной памяти, а #-таблицы - в tempdb, разницы в этом плане между ними на самом деле нет. И те и другие хранятся в tempdb, и, также, и те и другие одинаково буферизуются.
Область видимости: #-таблицы доступны на том уровне, на котором они создаются и на вложенных (@@nestlevel больше текущего). @-таблицы доступны только в рамках того batch-а или модуля, в котором они объявляются (впрочем, типированные @-таблицы на вложенные уровни можно передавать параметром).
Жизненный цикл: @-таблицы создаются неявно в самом начале того батча, в котором они объявлены, перед выполнением всех остальных команд (а если это модуль, то перед началом выполнения модуля), независимо от того, будет ли достигнута в процессе исполнения соответствующая declare инструкция, или нет. Вот такой код, например, вполне работает:
if 1 != 0 declare @table1 table (id int); else declare @table2 table (name varchar(20));
select * from @table1; select * from @table2; GO
уничтожаются @-таблицы после выхода из соответствующего батча или модуля, в котором они объявлены.
#-таблицы создаются тогда, когда встречается соответствующая create table инструкция; уничтожаются тогда, когда встречается соответствующая drop table инструкция, либо при уменьшении уровня вложенности (выхода из модуля или exec инструкции), или закрытии соединения (если #-таблица была создана на нулевом уровне вложенности).
Использование в функциях и процедурах: #-таблицы нельзя создавать в пользовательских скалярных и multi-line табличных функциях, @-таблицы - можно. Типированные @-таблицы можно передавать в функции и процедуры параметром. #-таблицы нельзя передавать в функции (хотя можно получить к ним доступ косвенно - через синоним). В процедурах #-таблицы, созданные на внешнем уровне - доступны.
Сollation: При создании @-таблиц столбцы строковых типов (если они присутствуют) наследуют collation от текущей БД. При создании #-таблиц столбцы строковых типов наследуют collation от tempdb, либо от текущей БД, если та является автономной (contained).
Индексы/ключи: До SqlServer 2014 на @-таблицах можно было задавать только уникальные ключи
declare @table table ( id int primary key, uid uniqueidentifier unique )
В SqlServer 2014 с добавлением inline-синтаксиса для создания индексов стало возможным добавлять неуникальные индексы
declare @table table ( value varchar(20), index ix_1 (value) )
В SqlServer 2016 стало возможным добавление уникальных и отфильтрованных индексов
declare @table table ( id int, value varchar(20), index ix_1 unique (value), index ix_2 (id) where value is NULL )
Индексы с include, а также специальные виды индексов на @-таблицах на настоящий момент не поддерживаются.
Компиляция запросов: Оптимизатор запросов во многих случаях полагает, что @-таблица содержит одну единственную строку. На @-таблицах не поддерживаются статистики по столбцам.
Транзакции: Изменение содержимого @-таблиц всегда происходит в системной транзакции, поэтому они нечувствительны к rollback
declare @table table (value int); create table #table (value int); begin tran; insert into @table values (1); insert into #table values (2); rollback; select * from @table; select * from #table; drop table #table;
Параллелизм: Запросы, меняющие содержимое @table (insert/update/delete) не могут использовать параллелизм. Запросы читающие из @table (select) могут иметь параллельный план.
Табличные подсказки: На @-таблицах нельзя использовать табличные подсказки (table hints), на #-таблицы такое ограничение не накладывается.
Другое: @-таблицу нельзя создать при помощи select * into @table from .... Для @-таблиц недоступны truncate table, alter table, create index

разобрать изменить и собрать

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


Ответ

для проведения таких действий вам потребуется:
dex2jar Java Decompiler ApkTool
Далее выполнить по следующим шагам:
Качаем dex2jar и извлекаем в папку, например С:\Decompile . Качаем Java Decompiler (например JD-GUI) и извлекаем файлы для удобства в ту же папку, куда и dex2jar. Качаем apktool и apktool-install-windows-r04-brut1.tar.bz2 и извлекаем файлы уже в системную папку. По умолчанию C:\Windows. (Не забыть скачать второй архив) Берем нужный apk файл и кладем в папку с dex2jar и Java Decompiler Открываем Командную строку (Обработчик команд Windows) в вышеупомянутой папке (В папке по пустому месте при зажатой кнопке Shift нажимаем правую кнопку мыши и выбираем Обработчик команд Windows). Вводим команду dex2jar <ваш apk файл> и если все прошло хорошо, в той же папке появится файл <название вашего файла>.apk.dex2jar.jar Запускаем jd-gui и открываем полученный на предыдущем шаге файл. (На Windows 7 открывать с правами администратора и с совместимостью Windows XP SP3) Выбираем пункт меню File-Save All Sources и сохраняем. Извлекаем полученный zip архив. Помещаем полученную папку в папку src (надо предварительно создать).(Что бы получилась примерно такая структура С:\Decompile\<название вашего файла>\src\com\android) Опять же в командной строке вводим команду apktool d <название вашего файла>.apk <название вашего файла>, где <название вашего файла>.apk-имя пакета, <название вашего файла>-папка для декомпиляции.
Если все хорошо, тогда в указанной папке будут исходники в двух форматах (java и smali), ресурсы и файлы AndroidManifest.xml, apktool.yml
Таким образом будут получены исходники. Правда после декомпиляции в коде есть, можно сказать, ошибки,например вместо true и false стоят 1 и 0 соответственно.

Различие между context и this

В андроиде есть context-ссылка, а на самой джаве есть this-ссылка. Так вот в чем разница контекста от зиса и можноли пример с контекстом а то я запутался в нем. Благодарю.


Ответ

this и Context – это принципиально разные вещи.
this – это ключевое слово языка Java. this – это ссылка на самого себя. Ссылка на объект, для которого был вызван метод.
Context (в android) – это абстрактный класс, предоставляющий методы для доступа к т.н. глобальной информации (к ресурсам, классам, для управления активити, сервисами и так далее).
Непосредственными субклассами классами Context являются классы ContextWrapper и MockContext. В свою очередь, прямыми субклассами класса ContextWrapper, в том числе, являются классы Application и Service, а непрямым – класс Activity
Пример с Context
getActivity().runOnUiThread(new Runnable() { @Override public void run() { // some actions } });
Здесь, для запуска кода в UI-потоке используется объект класса Activity (который является (непрямым) наследником класса Context).
Еще один пример с Context
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
Здесь в конструктор класса LinearLayoutManager передается объект класса Activity. Такой вызов, возможен, например, из фрагмента.
Из самой активити можно напрямую вызвать:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
так как this в методах активити является как раз объектом класса Activity

C# - Создание WPF окна в dll

Можно ли создать dll с функцией (в каком-то классе), которая строит WPF окно.


Ответ

Конечно!
Вы точно так же можете из любой функции создать окно:
var window = new MyWindow(); window.Show();
Не забудьте подключить сборки PresesntationCore, PresentationFramework и WindowsBase, а в свежей версии ещё и System.Xaml. И вы можете точно так же определить класс с окном в DLL, как и в основном приложении, через XAML.
Если у вас не получается добавить XAML для окна, вам понадобится вручную отредактировать csproj, как указано здесь

Если вы не в UI-потоке, и у вас WPF-приложение, вам придётся перебросить выполнение туда. Например, так:
Application.Current.Dispatcher.InvokeAsync(() => { var window = new MyWindow(); window.Show(); });

Если у вас консольное приложение, всё немного сложнее, т. к. у вас нету UI-потока. Вам нужно его создать. Как это делать, написано здесь
Вот рабочий пример:
var thread = new Thread(() => { var window = new MyWindow(); window.Show(); Dispatcher.Run(); });
thread.SetApartmentState(ApartmentState.STA); thread.Start();

Возможно ли средствами javascript прочитать сокеты по ip/порту стороннего сервера?

Сейчас с помощью php получаю данные из разных сокетов по ip:port (с помощью фунуции fsockopen). Это делается для получения играющей в данный момент композиции на разных радиостанциях:
$open = fsockopen($radioip,$radioport,$errno,$errstr,'.5'); if ($open) { fputs($open,"GET /7.html HTTP/1.1
User-Agent:Mozilla

"); stream_set_timeout($open,'1'); $read = fread($open,255); }
В результате основной javascript на главной странице регулярно обращается к этому php на сервере. Хочется, чтобы всё это работало без лишних запросов к серверу, а средствами самого браузера. Возможно ли сделать подобную функцию на javascript - чтобы передавать ей ip и port а в результате получать необходимые данные?


Ответ

К сожалению, любые запросы браузером вне вашего "Origin" возможны только, если на той отвечающей стороне в заголовках ответов есть Access-Control-Allow-Origin с вашим origin. Это дело все закрыто для безопастности, т.к. если бы можно было с любого сайта вызывать AJAXом другой - очень много всего плохого можно было бы делать так.
Подробнее про кросс-доменный AJAX например вот тут
Websockets при этом вам в данном случае совершенно не помогут, т.к. это отдельный протокол обмена данными между сервером и клиентом. И причем последнее время браузеры все чаще форсируют wss (шифрованные вебсокеты), для которых помимо поддержки Websockets еще и SSL на этом поддерживающем сервере нужен. Так что вам особо без промежуточного php скрипта не обойтись.
Если вы задаетесь этим вопросом по причине большой нагрузки на ваш сервер - стоит задуматься облегчением этого всего дела чем-то типа тех же websockets. Только не сторонними серверами, а вашим собственным. Который будет например сам с какой-то определенной частотой обновлять свой кэш по удаленным серверам и с определенной частотой(или по факту изменения) присылать информацию клиентам. В websockets соединение держится и в нем возможен двухсторонний диалог между клиентом и сервером. Тем самым клиентам не нужно будет постоянно обращаться к какой-либо страничке, а они просто получат websocket message по факту его отправки. Такое можно реализовать например на Node.js или ASP.net. На PHP лично я не видел подобных штук.

Прямоугольник с закругленными углами (xml, shape)

Можно ли программно сделать прямоугольник, у которого закруглить все углы кроме одного? Знаю, как сделать прямоугольник со всеми закругленными углами, но можно ли как-то сделать что бы один угол был не закругленным?
Для всех закругленных углов использую:


А нужно прямоугольник, который бы выглядел вот так:


Ответ


Как спроектировать проект? DTO, Anemic, MVVM

Что имеем:
Проект представляет из себя WPF приложение, взаимодействующее с сайтом, локальной БД и отображающее данные в пользовательском интерфейсе.
Пример работы:
На сайте есть что-то вроде топиков, которые время от времени обновляются. Нужно "скачивать" последнее состояние этих топиков и писать в локальную базу, назовем это синхронизацией. После синхронизации мы можем осуществлять быстрый поиск по базе, делать различные пометки, добавлять в избранное и т.д., взаимодействуя через интерфейс пользователя.
Видение структуры:
Модель получается одна, что для базы, что для MVVM. Однако еще я хочу создать также слой API, который будет взаимодействовать с сайтом и возвращать экземпляры моделей. Но тогда и в API понадобится модель.
В итоге получается 2 слоя (или 3?) - API и БД (+ MVVM). Работают с одной моделью. Значит нужно использовать Anemic модель? Или лучше разделить модели, для каждого слоя сделать свою?
Теперь про логику взаимодействия с VM. Если пользователь захочет получить топики по критериям, VM должен запустить синхронизатор, дождаться завершения и только после этого делать запросы к базе. Правильно ли будет синхронизаторы (парсеры), которые через API будут получать топики и обновлять их в базе, выделить в отдельные классы или предоставить эту логику VM-мам?

Что получилось:
Слой API, взаимодействующий с сайтом Слой БД Синхронизаторы, связывающие API и БД VM-ы, взаимодействующие с БД и API через синхронизаторы Общая DTO Anemic модель для API, БД и MVVM.

Правильно ли использовать данные разделения и подход к проектированию в целом?


Ответ

Жуткий поток сознания, который сложно понять.
У вас по сути десктопное приложение клиент к какому то сайту, которое позволяет забирать данные с сайта, просматривать их оффлайн и добавлять какую-то мета-информацию. А значит вот вам мои фломастеры...
Я предпочитаю подход, где есть модели(сущности) и сервисы, которые что-то могут сделать с этими сущностями, то есть anemic.
Модели (сущности) Не стоит плодить dto без надобности. А значит модель(сущность) "топик" будет одной для бд и для клиента сайта и для вьюмоделей, пока не потребуется иначе.
Слой доступа к данным - от него зависит всё. Я предпочитаю рассматривать его как внешнее хранилище. А это значит, что есть подобие Repository/Storage, из которого можно достать данные или положить. Он должен принимать сущности на своем внешнем уровне и внутри себя хранить как ему вздумается. Например быть разделенным на 2 слоя - верхний слой работает с сущностями, а нижний с простыми типами.
Тут много вариантов реализаций и от него зависит будут ли модели anemic. Я не приветствую rich model, которая знает как себя хранить, но модель, вырожденная в dto - тоже плохо, поэтому у меня модели содержат и данные и некоторые методы, которые мешают сохраняться напрямую и инода вынуждают использовать dto (но на практике у меня от dto больше проблем, чем от чистого anemic)
Клиент к сайту - модуль-обертка. В простом случае это 1-2 класса, которые прячут внутри себя сетевые запросы и трансляцию данных их в сущности. Вводить собственные типы данных на границе модуля (и возможно писать дополнительный адаптер/маппинг) есть смысл только если этот модуль будет переиспользоваться в других проектах или очень хочется большей изоляции модулей или у нас ORM, который сильно мешает. Иначе нарушаем YAGNI
Вид (WPF+MVVM) - WPF отображает, а MVVM предоставляет данные для отображения и связывает вид с моделью. MVVM дает данные для отображения и бегает в модель за данными или с просьбой выполнить какую то работу, но сам не содержит логику приложения. Его дело связать вид и логику приложения. Хотя даже при этом вьюмодели получаются жирными, поэтому некоторые добавляют контроллеры (MVVMC) к вьюмоделям, которые и берут на себя общение с моделью.
Синхронизация - это сервис, который относится к модели (не путать с сущностями), а не к виду, поэтому существует не как часть вьюмоделей.
Так мы получили условно модули. Работает все это вместе так:
Пользователь нажимает кнопку "синхронизировать" WPF кнопка забиндена на команду вьюмодели и срабатывает эта команда вьюмодель прямо или косвенно обращается к сервису синхронизации и просит "синхронизируй". Сама вьюмодель ничего большего не делает Сервис синхронизации используя клиент к сайту получает данные в виде сущностей и передает их слою базы данных для хранения. вьюмодель или ждет окончания синхронизации или использует события. вьюмодель отображает данные (лезет за ними в бд например) Те же сущности используются для отображения, ну разве что оборачиваются вьюмоделями(хорошая привычка).
Остались еще дополнительные данные, которых нет на сайте - пометки, метка "избранное" и так далее. Их можно хранить отдельно от сущности "топик", а можно как часть этой сущности (клиент к сайту просто не затронет те поля, что не знает). Декомпозиция слишком спорный процесс - я вот не люблю много колонок в бд, но сохранение и вычитывание графа тоже писать лениво.
Введение DTO - только при необходимости. DTO или сущности конкретного модуля (или использование простых типов) позволяют добиться большей изоляции модуля...но YAGNI требует подумать "а оно нам надо?"
Старайтесь обозначить границы модулей, чтобы работать только с ними. При этом внутренности модуля скрыты. Даже если нужна какая то внутренняя часть, то постарайтесь обеспечить доступ через фасад (границу модуля)

Использование async/await в Python

Почитал про использование async/await в других языках программирования и не совсем понял, как и когда их используют. Для чего они вообще нужны? С помощью них можно улучшить уже существующий код? В каких случаях не стоит их использовать?
PEP 492 introduced support for native coroutines and async / await syntax to Python 3.5. A notable limitation of the Python 3.5 implementation is that it was not possible to use await and yield in the same function body. In Python 3.6 this restriction has been lifted, making it possible to define asynchronous generators:
async def ticker(delay, to): """Yield numbers from 0 to *to* every *delay* seconds.""" for i in range(to): yield i await asyncio.sleep(delay)
PEP 530 adds support for using async for in list, set, dict comprehensions and generator expressions:
result = [i async for i in aiter() if i % 2]
Additionally, await expressions are supported in all kinds of comprehensions:
result = [await fun() for fun in funcs if await condition()]


Ответ

Смотрите. Async/await нужен для того, чтобы не блокировать поток выполнения на время ожидания какого-нибудь асинхронного события. Конструкция Async/await превращает по сути процедуру в корутину (сопрограмму): она прекращает своё выполнение на время await, дожидается асинхронного события, и возобновляет работу.
В не-async-варианте ожидание получается блокирующим, или нужно вручную делать трюки: запускать операцию и подписываться на её окончание. Async делает код более простым, линейным.
Пример (на псевдокоде):
Async:
DownloadToFile(url): filename = GetFilename() content = await DownloadUrl(url) WriteToFile(filename, content) ReportSuccess()
Не-async:
DownloadToFile(url): filename = GetFilename() BeginDownloadUrl(url, onfinished: lambda content: StoreContent(content, filename))
StoreContent(content, filename) WriteToFile(filename, content) ReportSuccess()
Вы видите, что без async контекст выполнения (локальные переменные и т. п.) приходится передавать в «хвост» функции (continuation) вручную. Если async-вызовов много, аналогичный код без async быстро становится сложным.

Важное отличие async- от синхронной функции — async-функция возвращается к вызывающему коду в момент первого выполнения await (если тот ещё не завершён). Вызывающий код может дождаться полного окончания работы при помощи await, а может и продолжить работу самостоятельно.

Использование async/await имеет смысл там, где у вас есть ожидание, не связанное с нагрузкой на процессор. Например, ожидание прихода данных из интернета, или чтения файла с диска. В этом случае вы освобождаете поток физический выполнения для системы, но логическое выполнение продолжается (после возврата из await).

Перенос rich текста между редакторами

Подскажите, как переносится форматирование и rich текст при копировании между совершенно разными редакторами, например Google Docs в браузере и Word на ПК. Что за технология? Более конкретно: есть html в буфере обмена, надо его преобразовать так, чтобы при вставке в редактор был уже текст.


Ответ

В буфере обмена данные могут храниться в нескольких представлениях (mime-type) одновременно. Приложение-источник (copy) помещает в буфер отдельную копию данных для каждого из поддерживаемых представлений, а потребитель (paste) выбирает наиболее удобный для себя формат, из тех которые понимает. В некоторых приложениях доступен выбор представления, которое будет использовано (см. Paste Special в ворде). Пример на Qt:
QByteArray svg=BOOST_PP_STRINGIZE( Foo ); QImage image; image.loadFromData( svg );
auto*mime=new QMimeData(); mime->setText("Foo"); // Как текст (будет понимать notepad). mime->setData( "text/html" , "Foo" ); // Поймет ворд mime->setData( "image/svg+xml" ,svg ); mime->setImageData( image ); // заполняет сразу несколько графических форматов auto*clip=QApplication::clipboard(); clip->clear(); clip->setMimeData(mime);

Возможно ли комбинировать несколько способов синхронизации?

Здравствуйте. Изучаю синхронизацию потоков в Java, и, как я понял из книги, существует несколько способов синхронизации: через ключевое слово synchronized, через использование блокировок ReentrantLock и через методы wait/notify
Правильно ли я выделил эти способы? Эти способы самодостаточны? Можно ли каждый из них использовать, не прибегая к остальным? Комбинация этих способов невозможна/нежелательна/допустима/желательна?


Ответ

Давайте по пунктам:
Нет, не верно. пара методов wait()/notify() работают только в synchronized блоке. Следовательно, они не могут быть выделены в отдельную категорию. Для разграничения доступа к разделяемому ресурсу используют:
synchronized блок, или метод. некоторые абстракции, в виде реализации интерфейса java.util.concurrent.Lock, различные семафоры, барьеры и пр. Их типы с избытком представлены в пакете java.util.concurrent. Впрочем, никто не запрещает написать какую нибудь свою реализацию.
2 и 3. Способы самодостаточны и их вполне, можно использовать не смешивая. Но как правило, в многопоточных программах, могут встретиться несколько типов синхронизации. Все сильно зависит от логики и условий использования. Приведу лишь несколько примеров:
если к ресурсу обращаются не так часто и не много потоков, то производительнее будет использовать блокировку основанную на CAS'ах, т.к. это позволяет покрутившись в цикле избежав парковки треда, захватить ресурс, пускай и затратив некоторое процессорное время. если у ресурса есть два режима: чтение и запись и относительно мало потоков, которые в него пишут, то используется java.util.concurrent.ReadWriteLock. Это позволяет нескольким потокам-читателям заходить в критические области. Но если появляется писатель, то читатели ждут, когда завершится чтение.

Как работает alignas()?

int distance(void* first, void* second) { return reinterpret_cast(first) - reinterpret_cast(second); }
int main() { alignas(16) int f[4]; alignas(1024) int s[4]; std::cout << distance(f, s);
return 0; }
Никак не могу понять как работает alignas(). Почему расстояние равно 2016, а без него 24?


Ответ

alignas - это новая штука с с++11 стандарта и предназначена, чтобы устаканить то, что творится в разных компиляторах. Чтобы не говорили разработчики других языков, но иногда нужно писать немножко низкоуровневого кода, чтобы получить существенный плюс в скорости.
Как известно, процессоры лучше работают с данными в памяти, если они выровнены по границе в 4/8/16 байт. А в некоторых случаях данные обязаны быть выровнены (например, с некоторыми SSE командами и на некоторых ARM процессорах).
Что такое выравнивание по границе? Это просто адрес, который кратен заданной степени двойки. То есть, адрес 24 выровнен по границе 2, 4, 8, но не 16. Адрес 1024 выровнен по 2, 4, 8, 16, 32 и многим другим. Можно сказать и по-другому - адрес, выровненный по границе 16 в бинарном виде заканчивается на 4 нуля.
alignas как раз и заставляет компилятор сделать это выравнивание. Да, часто это идет в ущерб памяти (появляются пустоты), но в некоторых случаях (с SSE) можно получить двукратный прирост просто по той причине, что адрес выровнен по границе 16/32. Почему так происходит? Все просто - современные процессоры уже давно не загружают данные по байту из памяти - они обычно грузят как минимум по 4 байта сразу, более того, грузят по выровненным адресам по границе 4. И если нужно загрузить 4 невыровненных байта, то процессору приходится делать это в три этапа - загружаем первые байт (но при этом загружаем 4 байта), потом загружаем вторую половину, а потом складываем в памяти. А так как операция обращения к памяти - медленная - это длится достаточно долго.
Нужно ли в своем коде постоянно писать выравнивание? Нет, не нужно. Компиляторы достаточно умные и сами могут догадаться. Но есть случаи, когда это лучше сделать.
переменная используется для SSE/MMX. переменная-массив, достаточно большого размера, по которому нужно будет много итерироваться (бегать). числодробилки.
Почему расстояние равно 2016, а без него 24?
а на ideone вообще получилось -252:)
alignas говорит "выровняй", а как именно разместить в памяти - это другое дело. В Вашем случае компилятор вначале разместил первую переменную по адресу кратному 16. Вторую, нужно разместить по адресу кратному 1024. Логично, что такое может быть как сразу (потому что первая переменная занимает ровно 16 байт, так и через много-много байт (мы же не знаем адреса первой переменной).
Многие компиляторы в отладочном режиме за массивами всегда добавляют несколько байт - для того, что бы препятствовать классическому выходу за пределы массива на один элемент. Поэтому, чтобы понять, почему там именно 2016 - нужно смотреть в конкретную версию компилятора и параметры компиляции.

Как получить время простоя программы?

А именно время простоя в котором не было переключения на окно программы.
При этом может происходит работа в других программах.


Ответ

Вот вам небольшой пример на WPF:
public partial class MainWindow : Window { Stopwatch sw = new Stopwatch(); // счётчик времени
public MainWindow() { InitializeComponent(); Activated += (o, args) => sw.Start(); Deactivated += (o, args) => sw.Stop(); if (IsActive) sw.Start();
// ну и отображение StartIdleTimeUpdating(); }
async void StartIdleTimeUpdating() { while (true) { await Task.Delay(250); Target.Text = sw.Elapsed.ToString(); } } }


Результат:

Передача данных в слот не работает (через метод connect)

Есть вот такой код:
test.h
class test : public QObject{ Q_OBJECT private: ............................................... public: test(); public slots: void txt(); signals: void ok(); };
test.cpp
test::test(){ ................................................ connect(p, SIGNAL(clicked()), SIGNAL(ok())); }
void test::txt(){ l->setText("ok"); }
main.cpp
.................................................... test a, b;
QObject::connect(&a, SIGNAL(ok()), &b, SLOT(txt())); QObject::connect(&b, SIGNAL(ok()), &a, SLOT(txt())); ....................................................
Работает он замечательно. Но стоит добавить параметры передачи значений в слот как код перестает работать. Вот пример:
test.h
class test : public QObject{ Q_OBJECT private: ................................................ public: test(); public slots: void txt(QString); signals: void ok(QString); };
test.cpp
test::test(){ ...................................................... connect(p, SIGNAL(clicked()), SIGNAL(ok("word"))); }
void test::txt(QString s){ l->setText("ok"); }
main.cpp
.................................................... test a, b;
QObject::connect(&a, SIGNAL(ok()), &b, SLOT(txt())); QObject::connect(&b, SIGNAL(ok()), &a, SLOT(txt())); ....................................................
Этот код собирается но слот не отрабатывает, и почему то в редакторе строка:
connect(p, SIGNAL(clicked()), SIGNAL(ok("word")));
подчеркивается красным но в консоли ошибок нет. В чем может быть причина?


Ответ

Ответ kff из комментария:
В connect нельзя задавать параметры слота. Параметр должен приходить из сигнала
Дополню, что если сигнатура сигнала и слота не совпадает, либо необходимо выполнить дополнительные действия, то можно использовать новый синтаксис соединения сигналов и слотов, появившийся в Qt5, и lambda-выражения:
QObject::connect(p, &QPushButton::clicked, this, [this]() { Q_EMIT ok("word"); });

Как использовать в std::condition_variable функцию член класса?

В .h
class A{ std::thread thread; std::mutex mutex; std::condition_variable cv; bool run; std::queue< ResourceData > queue; public: bool resource_empty( void ){return !this->queue.empty();} ...
В реализации
while( this->run ){ std::unique_lock lk(this->mutex); cv.wait( lk, /* Сюда нужно вставить указатель на функцию */ this->resource_empty ); // просто this->queue.empty не работает // cv.wait( lk, []{ return !this->queue.empty();} ); и так }
Работает только если функция вне класса и без параметров
Хочу чтобы поток ожидал пока поступят данные в очередь. Может быть тогда есть иной способ с использованием данных класса без std::condition_variable?


Ответ

Во-первых, всегда можно использовать метод wait без второго параметра.
Во-вторых, чтобы использовать внешнюю переменную в замыкании - ее надо сначала захватить:
cv.wait( lk, [this] { return !this->queue.empty(); } );
Писать this-> необязательно - в лямбде так же, как и в любом другом месте, можно обращаться к членам this просто по имени. Но захватывать this нужно все равно:
cv.wait( lk, [this] { return !queue.empty(); } );
Также существует универсальный способ - захват всех необходимых переменных по значению:
cv.wait( lk, [=] { return !queue.empty(); } );
или по ссылке:
cv.wait( lk, [&] { return !queue.empty(); } );
Пользоваться этими способами надо с осторожностью: бесконтрольный захват переменных может привести к утечкам памяти или повреждению памяти. Но применительно к cv.wait использование [=] или [&] ничем не грозит.