Уникальный идентификатор задачи для каждой задачи длительного сложного процесса

#c# #async-await #task

Вопрос:

У меня есть проект, который выполняет 100 задач одновременно для выполнения сложных действий, которые включают в себя ряд методов и несколько операций ввода-вывода БД. Для регистрации всех действий я использую базу данных SQLite. Поскольку все задачи записывают журнал одновременно, поэтому не имеет смысла читать журнал последовательно, поэтому я использовал идентификатор задачи, чтобы различать последовательность действий каждой задачи, но, к сожалению, нет гарантии, что идентификатор задачи всегда будет уникальным. В отличие от потока, где мы можем задать имя потока, назначив идентификатор GUID с помощью Thread.CurrentThread.Name

Кроме того, идентификатор задачи-это просто число, и оно всегда начинается с 1, поэтому в файле журнала есть несколько записей с одинаковым идентификатором, которые на самом деле не принадлежат одной задаче. Может ли кто-нибудь поделиться опытом, как создать/поддерживать уникальную задачу.Идентификатор для каждой задачи в нескольких асинхронных исполнениях приложения?

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

Комментарии:

1. Вам нужно создать экземпляр для каждого процесса. Экземпляр будет содержать уникальные свойства для каждого процесса, эквивалентные идентификатору задачи.

2. Вы можете перенести функциональность в свой собственный класс и самостоятельно использовать уникальный идентификатор (например, идентификатор GUID). Или вы можете использовать .GetHashCode() то, что не гарантированно будет уникальным, но оно сильно изменится.

3. Какие задачи создает ваше приложение? Являются ли они основанными на делегатах ( Task.Run с синхронным делегатом) или в стиле обещаний (асинхронные методы)? Или смесь того и другого?

4. Задача @TheodorZoulias. Запуск с синхронным

5. @S. ATTA.M, «Предложенная очередь редактирования заполнена». Пожалуйста, вы можете обновить свой вопрос, чтобы было ясно, что вы хотите, чтобы он был уникальным Task.Id для нескольких исполнений вашего приложения.

Ответ №1:

Идентификатор не гарантируется уникальным (см. Здесь). Если вам нужен уникальный идентификатор для каждого Task , то, похоже, вам нужен адаптер для TaskFactory :

 class TaskWrapper
{
    public int ID { get; set; }
    public Task Task { get; set; }
}

public class TaskWrapperFactory
{
    private object lockobj = new object();
    private int nextId = 0;

    public TaskWrapper StartNew(Action action)
    {
        int id = 0;
        
        lock(this.lockobj)
        {
            id = this.nextId;
            this.nextId  ;
        }

        return new TaskWrapper
        {
            ID = id,
            Task = Task.Factory.StartNew(action)
        };
    }
}
 

Комментарии:

1. Спасибо за ваш быстрый ответ. Это хорошая идея, но мне придется перенести этот объект на все вложенные методы, которых может быть около 100. В отличие от того, если мы создаем задачу Task.Run(()=>{ someMethod()}); и someMethod( ) вызывает SomeAnotherMethod (), то во всех вложенных методах мы можем получить идентификатор задачи, просто вызвав «Task.currentId» без передачи какой-либо ссылки из вызывающего метода. Как мы можем добиться того же самого?

2. @S. ATTA.M, Task.CurrentId не является изменяемым, поэтому любое постоянное решение потребует изменений кода, даже если они просто копируются и вставляются. Я уже знал о локальном хранилище потоков, и, как оказалось, тоже есть «Локальное хранилище задач». Смотрите AsyncLocal<T> подробнее. Похоже, что вы можете обновить TaskWrapperFactory статическое CurrentId свойство, которое может получить уникальный идентификатор каждой задачи. Кроме того, вам также придется последовательно использовать свой собственный заводской метод.

3. @S. ATTA.M, все методы, которые вызывают Task.CurrentId , осознают контекст, в котором они выполняются, что для меня было плохим запахом. Оказывается, что он следует шаблону окружающего контекста (анти) , и это может быть хорошей целью для рефакторинга. Если возможно, попробуйте ввести все необходимые параметры при запуске задачи. Это облегчит тестирование, потому что вам не нужно беспокоиться о каких-либо внешних контекстах.