• Как ускорить поиск элементов из статичного string[] по подстроке?

    VoidVolker
    @VoidVolker Куратор тега C#
    Dark side eye. А у нас печеньки! А у вас?
    Раз нет ограничений по памяти и надо максимально быстро, то можно разложить весь массив в дерево таблиц переходов с шагом в один символ на таблицу. Самый быстрый и самый затратный по памяти. Таблица на каждый символ - 256 байт. Скорость поиска зависит только от размера строки и не зависит от объема данных: один символ - один переход в таблице к следующей таблице или конец поиска, если ноль. Я так уже делал: использовать имеет смысл на объемах примерно от 4 гигабайт данных (чем больше объем - тем меньше затраты на каждый символ). Но, если память позволяет и цель именно в скорости - то вполне нормальная плата памятью за скорость. Можно сократить расход памяти, если перекодировать строки в кодировку по числу используемых символов. Тогда таблица переходов будет в несколько раз меньше. Более экономный и более медленный вариант - дерево массивов/списков с шагом в 2/4/8 символов, при этом в поиске сравнение не по символам делать, а сразу по 2/4/8 байт: т.е., работаем со строкой как с массивом байтов и получаем оттуда uint16/uint32/uint64 и их и сравниваем, ибо процессору все равно какую инструкцию выполнять - один байт сравнить или 8. Возможно, конечно, оптимизатор в поиске по строке это все и оптимизирует. Я давно уже не смотрю на результаты его работы - так что тут только опытным путем. Ну и щас еще других вариантов накидают с деревьями тоже.

    UPD1:
    Можно все несколько упростить (или усложнить - смотря с какой стороны смотреть), если перекодировать строки из стандартной кодировки во что-то более компактное либо самостоятельно сделать кодировку под набор данных.

    Еще можно ускорить, если искать в несколько потоков, разбив весь набор данных на несколько групп.

    UPD2:
    Таки нашел немного времени и откопал исходники для шарпа и провел несколько тестов по расходу памяти.

    Число строк / общий размер данных / итоговый размер дерева

    5 символов:
    1000000 / 55.9MB / 13.2GB
    2000000 / 111.6MB / 25.2GB

    10 символов:
    100000 / 8.1MB / 4.1GB
    200000 / 16.1MB / 8GB
    300000 / 24.2MB / 11.9GB
    400000 / 32.2MB / 15.7GB
    500000 / 40.3MB / 19.5GB

    15 символов:
    100000 / 10.5MB / 6.6GB
    200000 / 21MB / 13.1GB
    300000 / 31.5MB / 19.5GB
    400000 / 42MB / 25.8GB

    20 символов:
    100000 / 13MB / 9.1GB
    200000 / 25.9MB / 18.1GB
    300000 / 38.9MB / 27GB


    Максимальный размер дерева для глубины в 5 символов на платформе х64:
    • Для диапазона 0-255 - до 8Тб и до 4 311 810 305 узлов
    • Для диапазона 0-70 - до 13.5Гб и до 24 357 971 узлов

    Максимальный размер дерева для глубины в 4 символа для диапазона 0-255: ~17Гб и ~33Гб для х86 и для х64 соответственно и лимит в 16 843 009 узлов. Ну и в коде есть функция для вычисления максимального числа узлов и размера дерева.

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

    И соответственно код: https://github.com/VoidVolker/search-tree/tree/master (предупреждаю сразу: код старый, по сути экспериментальный, не вылизанный и вероятно приведет кого-то в ужас). Но, главное, что работает.
    код

    Тестовый код:
    static Random rnd = new Random();
    static string[] GenStrings(int cnt, int strLen)
    {
        string[] arr = new string[cnt];
        var i = 0;
        while (i < cnt)
        {
            var sb = new StringBuilder();
            for (var j = 0; j < strLen; j++)
            {
                sb.Append(rnd.Next(0, 256));
                //sb.Append(TAbc[rnd.Next(0, TAbc.Length)]);
            }
            arr[i++] = sb.ToString();
        }
        return arr;
    }
    
    var arraySize = 300000;
    var stringSize = 20;
    
    var GCStartArr = GC.GetTotalMemory(true);
    
    var strings = GenStrings(arraySize, stringSize);
    
    var GCEndArr = GC.GetTotalMemory(true);
    var GCStart = GC.GetTotalMemory(true);
    
    var tree = new ArrayTree<string>();
    foreach (string s in strings)
    {
        tree.Add(Encoding.UTF8.GetBytes(s), s);
    }
    
    var GCEnd = GC.GetTotalMemory(true);
    
    Console.WriteLine("Array x string size / Array memory used / Tree memory used");
    Console.WriteLine($"{arraySize} х {stringSize} / {BytesToString(GCEndArr - GCStartArr)} / {BytesToString(GCEnd - GCStart)}");
    Ответ написан
  • Как парсить HTML при помощи HttpClient?

    @ERAFY Автор вопроса
    У меня еще при помощи HttpWebRequest получилось сделать:
    HttpWebRequest http = (HttpWebRequest)WebRequest.Create(pathToHtml);
            WebResponse response = http.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader sr = new StreamReader(stream);
            string html = sr.ReadToEnd();
    
            // Создание экземпляра локальной переменной «doc».
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
    
            // Загрузка HTML кода в локальную переменную «doc».
            doc.LoadHtml(html);
    
            var x = doc.DocumentNode.SelectNodes(pathToHTMLTextNode).Elements("tr").ToList();

    Может кому пригодиться в будущем.
    Ответ написан
    Комментировать
  • Как парсить HTML при помощи HttpClient?

    tomnolane
    @tomnolane
    профессиональный разработчик
    способов много, но предложу использовать универсальный, пусть это и костыль, но много место не занимает, дополнительные (сторонние библиотеки не нужны...):
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication3
    {
        public static class Program
        {
            private static string html = "Ошибка";
    
            private static void Main()
            {
                ShowTags("https://www.yandex.ru/","a");
                Console.ReadKey();
            }
    
            private static async void ShowTags(string my_url, string tag = "a") // Тег по умолчанию для поиска, ищем теги <a></a>
            { 
                // Загружем страницу 
               string data = await GetHtmlPageText(my_url);
    
               if (!data.Contains("Ошибка"))
                { 
                    string pattern = string.Format(@"\<{0}.*?\>(?<tegData>.+?)\<\/{0}\>", tag.Trim());
                    // \<{0}.*?\> - открывающий тег
                    // \<\/{0}\> - закрывающий тег
                    // (?<tegData>.+?) - содержимое тега, записываем в группу tegData
    
                    Regex regex = new Regex(pattern, RegexOptions.ExplicitCapture);
                    MatchCollection matches = regex.Matches(data);
    
                    foreach (Match matche in matches)
                    {
                        Console.WriteLine(matche.Value);
                        Console.WriteLine("Содержание:");
                        Console.WriteLine(matche.Groups["tegData"].Value);
                        Console.WriteLine("---------------------------");
                    } 
                }
                else
                {
                    Console.WriteLine("Ошибка при загрузке со страницы: " + my_url);
                }
            }
    
            private static async Task<string> GetHtmlPageText(string url)
            {  
                await Task.Run(async()=>{
                   
                    // ... используем HttpClient.
                    using (HttpClient client = new HttpClient())
                    using (HttpResponseMessage response = await client.GetAsync(url))
                    using (HttpContent content = response.Content)
                    {
                        // ... записать ответ
                        string result = await content.ReadAsStringAsync();
                        if (html != null)
                        {
                            html = result;
                        }
                    } 
                });
                return html;
            }
        }
    }


    результат на примере yandex.:
    <a href="http://mail.yandex.ru"onclick="c(this,17,1080)">Войти&nbsp;в&nbsp;почту</a>
    Содержание:
    Войти&nbsp;в&nbsp;почту


    Regex работает быстрее чем остальные парсеры
    Ответ написан
  • Какая есть кросс-платформенная библиотека для аудио в C#?

    @KirMozor Автор вопроса
    Взял обёртку над ManagedBass как и советовал Vabkab
    Единственно, мне пришлось доустанавливать библиотеку libbass в ArchLinux (в AUR есть)
    Вот код если кому интересно:

    using ManagedBass;
    using System;
    
    namespace Yamux
    {
        public class Player
        {
            public static void PlayUrlFile()
            {
                // Init BASS using the default output device
                if (Bass.Init())
                {
                    // Create a stream from a file
                    var stream = Bass.CreateStream("/home/kirill/Downloads.mp3");
    
                    if (stream != 0)
                        Bass.ChannelPlay(stream); // Play the stream
    
                    // Error creating the stream
                    else Console.WriteLine("Error: {0}!", Bass.LastError);
    
                    // Wait till user presses a key
                    Console.WriteLine("Press any key to exit");
                    Console.ReadKey();
    
                    // Free the stream
                    Bass.StreamFree(stream);
    
                    // Free current device.
                    Bass.Free();
                }
                else Console.WriteLine("BASS could not be initialized!");
            }
        }
    }


    Но я всё равно не могу прослушивать музыку из интернета :(
    Что делать?
    Качать сырые байтики и тут-же передавать их в плеер?
    Но как это сделать?
    Я не разу подобным не занимался
    Ответ написан
    1 комментарий
  • Что выбрать Windows Forms или WPF?

    mindtester
    @mindtester
    http://iczin.su/hexagram_48
    1 - если смотреть в будущее (вин10) и метить на витрину магазина МС - еще лучше сразу UWP

    2 - но мордочки для винформ тоже есть:
    - https://github.com/Wagnerp/Krypton-NET-4.7
    - https://github.com/N-a-r-w-i-n/MetroSet-UI

    3 - если метить на трудоустройство в корпоративный сектор - все популярные библиотеки компонентов .net, типа DevExpress, Telerik, Syncfusion и тд - дают триалы, не грех поиграть (там и формы, и впф и увп, и веб..)

    отдельно про Syncfusion - у них есть хитрая лицензия для практически не ограниченного бесплатного использования, даже коммерческого в каких то пределах (но подробности уже у них на сайте ищите)

    ps

    если чисто для десктопа - формы+мордочки проще и мало в чем уступают, а работа с треем по дефолту доступна именно в формах

    минус и форм и впф - встроенный браузер - это IE (тут отвечал подробно - придется осваивать или CEF# или GeckoFX, новичку это будет сложно)

    ... а в UWP - уже Edge, там все гораздо веселее

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

    pps

    вот статья от крутого эксперта, первые два пункта как раз вам по теме почитать.. статья ооочень старая, но суть далеко не все "гуру" знают даже сегодня ;))
    Ответ написан
    Комментировать
  • Что надо знать для написания софтов на C#?

    @itgood
    тебе надо учить сетевое и системное программирование для того что бы писать чекеры < могу помочь с этим
    Ответ написан
    Комментировать
  • Как правильно парсить ссылку на видео?

    Stalker_RED
    @Stalker_RED
    Могу подсказать про ютуб, в прошлом году с ним возился.
    Получаем youtubeVideoId
    /**
    * выдергивает videoId из url или embed
    * тесты здесь: http://jsfiddle.net/1j5do56g/1/
    *
    * @param string input
    * @returns string youtube video id
    */
    function youtubeGetID(input){
        var r = input.replace(/(>|<)/gi,'').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/)
        if(r[2] !== undefined) {
            return r[2].split(/[^0-9a-z_\-]/i)[0]
        } else {
            r = input.match(/^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/)
            if(r && r[1] !== undefined) {
                return r[1]
            }
            else return input
        }
    }

    Тест: jsfiddle.net/1j5do56g/1

    Делаем ссылку и используем как src для iframe
    // parse and update id
            var youtubeId = youtubeGetID(field.val())
            field.val(youtubeId)
    
            // update iframe
            var newSrc = 'http://www.youtube.com/embed/' + youtubeId
            var iframe = field.closest('.panel-body').find('iframe')
            iframe.attr('src', newSrc)


    С остальными сервисами такая-же история. Можете поискать готовые решения.
    Ответ написан
  • Возможно ли с web сайта сделать запрос к камере мобильного телефона?

    Exploding
    @Exploding
    wtf?
    Ну вот например.
    https://ruseller.com/lessons.php?rub=32&id=2756
    И не обязательно мобильного.
    К камере ноута, вебке... Че там ещё бывает))
    Вобщем к любой доступной камере на устройстве. Единственное, что я так и не дорыл, можно ли переключаться между камерами если их несколько. Например в телефоне фронтальная и задняя. Но у меня по-умолчанию запускалась задняя (основная).
    Но в любом случае (кроме флеша) доступ к камере будет возможен только при наличии https протокола

    UDP. Кому интересно https://developer.mozilla.org/en-US/docs/Web/API/N...
    И вертеть там можно и крутить камеры и про ограничения все красным по синему написано, бери да читай, так нет же, на кофейной гуще гадать надо))!! (это я о себе)
    Но оно мне щас не надо, а букаф там очень много, поэтому разбирайтесь:)
    Ответ написан
    2 комментария
  • С чего начать выполнять задание ASP.NET?

    firedragon
    @firedragon
    Не джун-мидл-сеньор, а трус-балбес-бывалый.
    1. создать проект
    2. создать модели
    3. создать вьюшки
    4. создать Area для аутентификации (это уже есть просто щелкните несколько раз)
    5. грамотно настроить заполнение первичными данными
    6. реализовать корзину с использованием React, Angular, VUE
    7. админку для управлениями пользователями
    8. админку для отчетов о покупке, в соответствии с ролью пользователя в системе
    9. добавьте тестов
    10. заполните appsettings.Development.json etc
    Ответ написан
    Комментировать
  • Что нового в ASP.Net MVC6?

    Funbit
    @Funbit
    MVC 6 практически полностью новый фреймворк, построенный на базе ASP.NET vNext.
    Основные изменения на вскидку:
    - избавление от System.Web зависимости, которое позволит существенно ускорить выполнение запросов (судя по цифрам почти на порядок)
    - объединение с WebAPI и SignalR (в прошлых версиях часть классов дублировалась в разных неймспейсах)
    - vNext !!! (компиляция исходников на лету, деплоймент ВСЕХ зависимостей вместе с приложением, новый деплоймент через PowerShell, и еще куча всего принципиально нового)
    - возможность запускать MVC приложения вне IIS, базируясь на OWIN (пока это можно делать только с WebAPI и SignalR). Как следствие - возможность работы на Mono (маке, линуксе и т.п.)
    - улучшения в Attribute Routing'е
    - еще много мелочей

    Большой плюс в том, что новая платформа теперь полностью открыта (исходники на гитхабе) и вы можете опробовать её уже сейчас: www.asp.net/vnext
    Ответ написан
    Комментировать
  • Плеер на C#

    antonitpro
    @antonitpro
    MCTS, CCNA
    Приветствую.
    Возможно поздно, но все таки...
    Возможно вариант устроит вас (WnForms, c#):
    using Microsoft.DirectX.AudioVideoPlayback;
    
    
    private Video video;
    private string[] videoPaths;
    private string folderPath = @"C:\Users\Dell XPS\Desktop\Videos\";
    private int selectedIndex = 0;
    private Size formSize;
    private Size pnlSize;
    
    public Form1()
    {
        InitializeComponent();
    }
    
    private void Form1_Load(object sender, EventArgs e)
    {
        formSize = new Size(this.Width, this.Height);
        pnlSize = new Size(pnlVideo.Width, pnlVideo.Height);
    
        videoPaths = Directory.GetFiles(folderPath, "*.wmv");
    
        if (videoPaths != null)
        {
            foreach (string path in videoPaths)
            {
                string vid = path.Replace(folderPath, string.Empty);
                vid = vid.Replace(".wmv", string.Empty);
                lstVideos.Items.Add(vid);
            }
        }
        lstVideos.SelectedIndex = selectedIndex;
    }
    
    private void lstVideos_SelectedIndexChanged(object sender, EventArgs e)
    {
        try
        {
            video.Stop();
            video.Dispose();
        }
        catch { }
    
        int index = lstVideos.SelectedIndex;
        selectedIndex = index;
        video = new Video(videoPaths[index], false);
        video.Owner = pnlVideo;
        pnlVideo.Size = pnlSize;
        video.Play();
        tmrVideo.Enabled = true;
        btnPlayPause.Text = "Pause";
        video.Ending += Video_Ending;
        lblVideo.Text = lstVideos.Text;
    }
    
    private void Video_Ending(object sender, EventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            System.Threading.Thread.Sleep(2000);
    
            if (InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    NextVideo();
                }));
            }
        });
    }
    
    private void NextVideo()
    {
        int index = lstVideos.SelectedIndex;
        index++;
        if (index > videoPaths.Length - 1)
            index = 0;
        selectedIndex = index;
        lstVideos.SelectedIndex = index;
    }
    
    private void btnNext_Click(object sender, EventArgs e)
    {
        NextVideo();
    }
    
    private void btnPrevious_Click(object sender, EventArgs e)
    {
        PreviousVideo();
    }
    
    private void PreviousVideo()
    {
        int index = lstVideos.SelectedIndex;
        index--;
        if (index == -1)
            index = videoPaths.Length - 1;
        selectedIndex = index;
        lstVideos.SelectedIndex = index;
    }
    
    private void btnPlayPause_Click(object sender, EventArgs e)
    {
        if (!video.Playing)
        {
            video.Play();
            tmrVideo.Enabled = true;
            btnPlayPause.Text = "Pause";
        }
        else if (video.Playing)
        {
            video.Pause();
            tmrVideo.Enabled = false;
            btnPlayPause.Text = "Play";
        }
    }
    
    private void btnFullscreen_Click(object sender, EventArgs e)
    {
        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;
        video.Owner = this;
    }
    
    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Escape)
        {
            //exit full screen when escape is pressed
            FormBorderStyle = FormBorderStyle.Sizable;
            WindowState = FormWindowState.Normal;
            this.Size = formSize;
            video.Owner = pnlVideo;
            pnlVideo.Size = pnlSize;
        }
    }
    
    private void trackVolume_Scroll(object sender, EventArgs e)
    {
        video.Audio.Volume = trackVolume.Value;
    }
    
    private void btnVolume_Click(object sender, EventArgs e)
    {
        trackVolume.Visible = !trackVolume.Visible;
    }
    
    private void tmrVideo_Tick(object sender, EventArgs e)
    {
        int currentTime = Convert.ToInt32(video.CurrentPosition);
        int maxTime = Convert.ToInt32(video.Duration);
    
        lblVideoPosition.Text = string.Format("{0:00}:{1:00}:{2:00}", currentTime / 3600, (currentTime / 60) % 60, currentTime % 60)
                                + " / " +
                                string.Format("{0:00}:{1:00}:{2:00}", maxTime / 3600, (maxTime / 60) % 60, maxTime % 60);
    }
    Ответ написан
    Комментировать
  • Cписок ресурсов чтобы вспомнить С#?

    rad95
    @rad95
    Ответ написан
    Комментировать
  • Чем заменить sqlite3?

    saboteur_kiev
    @saboteur_kiev
    software engineer
    Суть sqlite - отсутствие сервера. Вся логика - в библиотеке.
    Но именно поэтому блокируется доступ - потому что к одному файлу может подключаться только одно приложение.
    Сервер решает этот вопрос тем, что именно сервер и является тем одним приложением, которое работает с файлом, а все остальные работают через сервер.

    Поэтому без сервера архитектурно не должно быть многопользовательского доступа к файлу.
    Ответ написан
    Комментировать
  • Проблема с пространством using System.Web.Http?

    @Melz
    Удалите и снова установите/обновите Microsoft.AspNet.WebApi через NuGet. Возможно прийдется перезапустить студию.
    Ответ написан
    Комментировать
  • Виртуальные рабочие столы на Linux?

    risik
    @risik
    Программист
    Есть xrdp. Не так давно развлекался по этому поводу и поставил такой сервер на базе (x)ubuntu. Доступ снаружи — rdp с логином/паролем, что очень удобно для виндовых пользоваталей — им не надо никаких новых клиентов, а он внутри поднимает VNC сессию. Схема вполне рабочая. Если будут вопросы, могу помочь.
    Ответ написан
    2 комментария
  • Как можно стилизовать value тега input?

    Mesuti
    @Mesuti
    Сделал для Вас готовые примеры

    Css https://jsfiddle.net/wo6k7vrd/1/

    jQuery https://jsfiddle.net/wo6k7vrd/2/

    JS чистый https://jsfiddle.net/wo6k7vrd/3/
    Ответ написан
    Комментировать
  • Локальный клиент парсинга XML и обновления SQLite таблицы (C#). Возможно ли оптимизация?

    Nipheris
    @Nipheris Куратор тега C++
    Встал вопрос об оптимизации данного действия, потому как на обновление таблицы уходит минимум 2 минуты.

    Ну это известный прикол что по-умолчанию SQlite делает транзакцию на каждый insert. Запустите транзакцию и закоммитьте её один раз и все строки вставятся за секунду максимум.

    Вы начали выдумывать какие-то мегаспособы ускорения, не исследовав корень проблемы. А корень в том, что на транзакцию SQLite создаёт файл отката, и когда таки транзакций 40000, это будет столько же операций пересоздания файла. Это просто пздц какая тяжелая операция для файловой системы, и ни процессор ни многопоточность вообще не при чём. Могли бы догадаться сами, т.к. 40000 небольших записей это вообще не объём.

    Решение гуглится за 20 секунд и написано в FAQ по SQLite: www.sqlite.org/faq.html#q19
    Ответ написан
    Комментировать
  • Как обработать выборку из базы построчно?

    @Sumor
    Хоть так
    using(var reader = sqliteCommand.ExecuteReader())
    {
      while(reader.Read())
      {
        // вызов вашего метода для конкретной строчки
      }
    }

    Хоть так
    using(var reader = sqliteCommand.ExecuteReader())
    {
      // вызов вашего метода для reader, где вы будете сами перебирать строчки  
    }


    А если хотите поиграться с делегатами (если у вас, например, несколько вариантов обработки методами всей базы)
    Тогда передаёте хоть банальный Action (в том числе и в виде лямбда выражения) в функцию считывания и...

    void Do()
    {
      DoSmthWithDB((Action<DataReader>)((reader) => {Console.WriteLine(reader[0].ToString());}));
    }
    
    void DoSmthWithDB(Action<DataReader> myAction)
    {
    ...
    // Создание команды к БД
    ...
    using(var reader = sqliteCommand.ExecuteReader())
    {
      while(reader.Read())
      {
        myAction(reader); // Action<DataReader> переданный в виде параметра
      }
    }
    }
    Ответ написан
    Комментировать