Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/30: Рейтинг темы: голосов - 30, средняя оценка - 4.67
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553

Асинхронный вызов функции

05.03.2019, 17:09. Показов 5921. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
с потоками еще не имел дело как и с асинхронностью, поэтому пишу сюда.

у меня есть 2 функции, которые выполняются последовательно. Одна пишет данные в базу, другая пишет логи для этих данных,
что-то вроде этого:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void WriteLog(ToSave<T> items)
{
     ChangeLogHelper.WriteInsert(items);
}
private void Save(ToSave<T> items)
{
    DatenManagerHelper.Save(items);
}
 
//где-то в коде
private void MyFunc()
{
     Save(items);
     WriteLog(items);
}
мне нужно,чтобы запись логов происходила асинхронно, т.е. чтобы управление программой вернулось к пользователю, т.к. функция очень медленная..

сделал так, но оно не работает:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//сделал функцию MyFunc c возможностью асинхронного вызова
private async void MyFunc()
{
     Save(items);
     await WriteLogAsync(items);
}
//добавил след. функцию
private Task WriteLogAsync(ToSave<T>items)
{
     var t = new Task(() => WriteLog(items);
     t.Start();
 
     return t;
}
в чем ошибка?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
05.03.2019, 17:09
Ответы с готовыми решениями:

Асинхронный вызов функции
Добрый день. нужна помощь в освоении столь непростого дела как многоопытность )). Нужно сделать программку которая в фсинхронной функции...

Асинхронный вызов функции
Существует функция Get_Send. Собственно ничего не возвращает, другие потоки не трогает, как её можно попроще выполнить асинхронно ? ...

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

13
 Аватар для Immo
692 / 509 / 238
Регистрация: 02.10.2012
Сообщений: 1,741
05.03.2019, 17:48
Лучший ответ Сообщение было отмечено hamin как решение

Решение

C#
1
2
3
4
5
static async void SaveAndWriteLog(ToSave<T> items)
        {
            await Task.Run(() => Save(items));
            await Task.Run(() => WriteLog(items));
        }
Добавлено через 2 минуты
и модификаторы доступа к функциям поменяй с private на static
1
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
05.03.2019, 17:50  [ТС]
Immo,

спасибо, все работает
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
05.03.2019, 20:22
Лучший ответ Сообщение было отмечено hamin как решение

Решение

Immo, так оно асинхронно запустит один метод, дождется его выполнения и запустит второй. Вот попробуйте этот пример
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Program
    {
        static void Main(string[] args)
        {
            SaveAndLogFunc();
            Console.Read();
        }
        static async void SaveAndLogFunc()
        {
            await Task.Run(() => save());
            await Task.Run(() => write());
        }
        static void save()
        {
            Console.WriteLine("Начало записи БД");
            Thread.Sleep(10000);
            Console.WriteLine("Конец записи БД");
        }
        static void write()
        {
            Console.WriteLine("Начало записи логов");
            Thread.Sleep(10000);
            Console.WriteLine("Конец записи логов");
 
        }
    }
hamin, чтобы запустить их параллельно, await нужно указать в отдельном методе.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 class Program
    {
        static void Main(string[] args)
        {
            SaveAndLogFunc();
            Console.Read();
        }
        static void SaveAndLogFunc()
        {
            save();
            write();
        }
        static async void save()
        {
            await Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Начало записи БД");
                Thread.Sleep(10000);
                Console.WriteLine("Конец записи БД");
            });
        }
        static async void write()
        {
            await Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Начало записи логов");
                Thread.Sleep(10000);
                Console.WriteLine("Конец записи логов");
            });
        }
    }
Добавлено через 40 секунд
С виду они кажутся похожи, но работают по разному
1
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
06.03.2019, 11:22  [ТС]
Рядовой,

да, действительно. Спасибо за пример.
0
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
07.03.2019, 16:34  [ТС]
возникла следующая проблемка..

сделал такой метод:
C#
1
2
3
4
private static async void WriteLogAsync(ToSave<T> items)
{
     await Task.Factory.StartNew(() => Log(items));
}
и вызывается он в методе save
C#
1
2
3
4
5
6
7
private static void save(ToSave<T> items)
{
     //сохранение данных...
 
    //запись логов
    WriteLogAsync(items);
}
функция запускается параллельно и работает дальше.. после того, как данные сохранились идет снова обращение в бд по чтению этих новых данных и тут возникает проблемка.. чтение данных длится примерно 60 секунд, потом продолжается работа, причем в это время логи продолжают писаться. Когда же отключаю запись логов, все работает быстро.. такое чувство, что параллельность не до конца происходит в фоне..
0
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
07.03.2019, 17:41
hamin, в приведенном коде не вижу проблемы, нужно больше кода.
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
07.03.2019, 19:57
hamin,
C#
1
2
3
4
5
6
7
private static void save(ToSave<T> items)
{
     //сохранение данных...
 
    //запись логов
    WriteLogAsync(items);
}
вы записываете данные, как только они записались, начинается асинхронная запись логов, в итоге параллельно задачи не запускаются.

Добавлено через 32 секунды
запускаются последовательно, но в разных потоках
0
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
11.03.2019, 19:49  [ТС]
Цитата Сообщение от Рядовой Посмотреть сообщение
вы записываете данные, как только они записались, начинается асинхронная запись логов, в итоге параллельно задачи не запускаются.
как раз этого я и добивался. сначала происходит запись в бд и если она успешна, запускается в фоне запись логов, далее следует функция обновления интерфейса, т.е. это выглядит так:

C#
1
2
3
4
5
6
private static void save(ToSave<T> items)
{
     Save();
     WriteLogAsync(items);
     UpdateView();
}
т.к. запись логов осуществляет очень древняя библиотека и она очень медленная, мы решили запускать ее в фоне, чтобы не ждать когда она закончит свою работу. все вроде бы работает как надо, но при вызове UpdateView загружает данные около минуты, хотя обычно ему требуется 2-3 секунды. если же убираю запись логов, все работает в штатном режиме

Добавлено через 2 минуты
в чем может быть причина даже понятия не имею. в updateview происходит обычный вызов процедуры, который по айди загружает новые, только что сохраненные данные и отображает их на экране
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
11.03.2019, 20:50
hamin, ну так гадать можно долго.
как вариант - разные потоки обращаются к одному залоченому объекту.
Если нет - ставьте stopwatch в метод UpdateView и тестите с записью логов и без. Надо искать узкое место
0
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
12.03.2019, 11:51  [ТС]
Рядовой,

я вот тут подумал, может быть проблема в количестве потоков? функция save вызывается рекурсивно для всех связанных объектов, т.е. в данном случае она вызывается где-то 7-8 раз, т.е. создается 7-8 потоков, где записываются логи. где-то читал, что количество потоков не должно превышать количество ядер?
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
12.03.2019, 12:20
hamin, если количество потоков больше, чем количество ядер, происходит переключение контекста - тяжелая операция сохранения и восстановления регистров.
Покажите метод save
0
 Аватар для Immo
692 / 509 / 238
Регистрация: 02.10.2012
Сообщений: 1,741
12.03.2019, 12:58
Цитата Сообщение от Рядовой Посмотреть сообщение
hamin, если количество потоков больше, чем количество ядер, происходит переключение контекста - тяжелая операция сохранения и восстановления регистров.
Покажите метод save
все зависит от процессора, тут тоже можно бесконечно долго гадать, обычно потоков в 2 раза больше чем ядер.

во вторых, вы случайно не пишите всеми потоками в один файл?
0
880 / 559 / 291
Регистрация: 21.11.2012
Сообщений: 1,553
12.03.2019, 13:53  [ТС]
Рядовой,

Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        public static void Save<TKey>(
            IList<T> newItems,
            IList<T> oldItems,
            Func<T, TKey> getID,
            Action<T> setParentID,
            Action<IList<T>> saveEntity,
            Action<IList<T>> deleteEntity,
            Action<IList<T>, IList<T>> saveSubEnties,
            LogItems logItems = null
            )
        {
            ArgumentHelper.AssertNotNull(saveEntity, "saveEntity");
            ArgumentHelper.AssertNotNull(deleteEntity, "deleteEntity");
 
            ToSave<T> items = ToSave<T>.GetEntities<TKey>(newItems, oldItems, getID);
 
            if (items == null)
                return;
 
            var updIns = new List<ItemToSave<T>>();
 
            updIns.AddRange(items.InsertedEntities);
            updIns.AddRange(items.UpdatedEntities);
 
            updIns.NullAsEmtpy().ForEach(i =>
            {
                setParentID?.Invoke(i.NewValue);
            });
 
            saveEntity(updIns.NullAsEmtpy().Select(x => x.NewValue).ToList());
 
            if (saveSubEnties != null)
            {
                var newV = updIns.NullAsEmtpy().Where(x => x.NewValue != null).Select(x => x.NewValue).ToList();
                var oldV = updIns.NullAsEmtpy().Where(x => x.OldValue != null).Select(x => x.OldValue).ToList();
 
                saveSubEnties(newV, oldV);
            }
 
            if (items.DeletedEntities.Count > 0)
            {
                if (saveSubEnties != null)
                {
                    var nv = items.DeletedEntities.Where(x => x.NewValue != null).Select(x => x.NewValue).ToList();
                    var ov = items.DeletedEntities.Where(x => x.OldValue != null).Select(x => x.OldValue).ToList();
                    saveSubEnties(nv, ov);
                }
 
                deleteEntity(items.DeletedEntities.Where(x => x.OldValue != null).Select(x => x.OldValue).ToList());
            }
            WriteLogAsync(items);
        }


логи:

Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        private static void Log(ToSave<T> items)
        {
            items.InsertedEntities.NullAsEmtpy().ForEach(i =>
            {
                var s = i.NewValue.GetPrimaryKey();
                var st = i.NewValue;
 
                ChangeLogHelper.WriteInsert<T>(i.NewValue.GetPrimaryKey(), i.NewValue);
            });
 
            items.UpdatedEntities.NullAsEmtpy().ForEach(i =>
            {
                if (!ComparisonHelper.AreBusinessEqual<T>(i.OldValue, i.NewValue))
                {
                    ChangeLogHelper.WriteUpdate<T>(i.NewValue.GetPrimaryKey(), i.OldValue, i.NewValue);
                }
            });
 
            items.DeletedEntities.NullAsEmtpy().ForEach(i =>
            {
                ChangeLogHelper.WriteDelete<T>(i.OldValue.GetPrimaryKey(), i.OldValue);
            });
        }
 
        public static async void WriteLogAsync(ToSave<T> items)
        {
            await Task.Factory.StartNew(() => Log(items));
        }


Добавлено через 47 минут
все, разобрался. проблема была, видимо, в количестве потоков. сделал путем добавления параметра logItems в функцию, где собираются все данные для записи логов, после полной отработки метода save запускаю запись логов, работает как и должно. Всем спасибо за помощь
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.03.2019, 13:53
Помогаю со студенческими работами здесь

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

Асинхронный вызов делегата и его принудительная остановка
Здравствуйте, с помощью данной конструкции вызываю асинхронный метод в программе: public partial class winEditor : Window { ...

Правильно ли выполнено задание? (Асинхронный вызов делегата)
Собственно, вот задание: Объявить делегат, который ссылается на произвольную бинарную операцию над целыми числами, т.е. int Op(int x,...

Асинхронный вызов: Abort и Callback
Всем привет! Недавно начал разбираться с многопоточностью в .NET. 1) Мне нужно запустить поток так, чтобы после его завершения ...

Асинхронный вызов функции, возможно через другой поток
Привет! Есть какой - то класс, содержащий какое-то поле (переменную) и какую - то функцию, изменяющую эту переменную. ну например такой ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru