Многопоточный консольный массив - PullRequest
0 голосов
/ 26 сентября 2018

В последнее время я боролся с многопоточностью.У меня есть консольное приложение C #, которое обучает нейронные сети.Я создаю поток через задачу для каждой сети, которую я собираюсь тренировать.Я создал событие обновления статуса для своего класса тренера, на который подписывается родительский класс.В этом обработчике событий я обновляю массив состояний новым статусом этой модели.В этом доступе к массиву я вижу «тупиковый» тип поведения.Я понимаю, что это не каноническое определение тупика, но я не могу придумать лучшего термина для описания ситуации.Ниже мой код.Я сжал это столько, сколько смог.

Я ценю любую помощь.Спасибо

Родительский код

public class TrainingEngine
{
    public enum UpdateStatus
    {
        Untrimmed = 0,
        Trimmed,
        Completed
    }

    private class TrainingStatus
    {
        public int Epoch { get; set; }
        public UpdateStatus UpdateStatus { get; set; }
    }

    private static readonly object printLock = new object();

    private ConcurrentDictionary<int, TrainingStatus> trainingStatus;

    ...other stuff...

    private void UpdateEpochCompleted(TrainingStatus newStatus)
    {
        trainingStatus[newStatus.ThreadId] = newStatus;
        PrintUpdate($"Model {newStatus.ThreadId + 1} completed epoch {newStatus.Epoch}.");
    }

    private void PrintUpdate(string trigger)
    {
        lock (printLock)
        {
            logger.Info(""); /***** DEADLOCKS HERE *****/

            logger.Info($"  {trigger}");
            foreach (TrainingStatus status in trainingStatus.Values)
            {
                if (status.Status == TrainingStatus.UpdateStatus.Completed)
                {
                    logger.Info(
                        $"    {status.Status.ToString()} model {status.ThreadId + 1}",
                        100);
                }
                else
                {
                    logger.Info(
                        $"    {status.Status.ToString()} model {status.ThreadId + 1} working on epoch {status.Epoch} / {epochCount}",
                        100);
                }
            }
        }
    }
}

Определение работника

public class NetworkTrainer
{
    IProgress<TrainingStatus> UpdateCompleted { get; set; }


        private double TrainNetwork(ActivationNetwork network,
            int epochCount,
            int geneCount,
            double[][] inputData,
            double[][] outputData,
            int threadId,
            bool trimmedModel)
        {

            for (int idxEpoch = 0; idxEpoch < epochCount; ++idxEpoch)
            {
                error += teacher.RunEpoch(inputData,
                    outputData);

                UpdateCompleted?.Report(new TrainingStatus
                {
                    Epoch = idxEpoch,
                    Status =  (trimmedModel) ? TrainingStatus.UpdateStatus.Trimmed : TrainingStatus.UpdateStatus.Untrimmed,
                    ThreadId = threadId,
                });
            }

            return error;
        }
}

Скриншот тупика enter image description here

1 Ответ

0 голосов
/ 04 октября 2018

Я нашел проблему.Во-первых, я хотел бы поблагодарить всех, кто помог мне, особенно Panagiotis Kanavos и usr.Первоначально у меня было плохо написанное заявление о блокировке, которое было уязвимо для повторного входа.Глядя на мой код, я не мог понять, как может возникнуть такое условие.В конце концов, каждая эпоха обучения займет около 30 минут.После некоторого расследования я узнал, что когда я нажимаю на окно терминала и оставляю белый квадрат на окне (маркер), я блокирую доступ к терминалу.Это означало, что мои потоки больше не могли писать в терминал;Я был в тупике.Иногда я занимался другими вещами на ноутбуке, пока он обучал мои модели, и нажимал на терминал, чтобы увидеть текущее состояние.

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

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