task.Wait (TimeSpan) не работает должным образом? - PullRequest
1 голос
/ 05 мая 2020

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

private bool CheckIfFieldExists(string toSearch, string type) {
    bool doesFieldExist = false;
    if (type == "username") {
        Task t = playerDataDB.Child("Player").Child(toSearch).GetValueAsync().ContinueWith(task => {
            if (task.IsFaulted) {
                Debug.Log("Task was faulted: Pulling from database");
                return;
            }
            else if (task.IsCompleted) {
                DataSnapshot snap = task.Result;
                if (snap.Exists) {
                    Debug.Log("field exists");
                    doesFieldExist = true;
                } else {
                    Debug.Log("field doesnt exist");
                    return;
                }
            }
        });
        TimeSpan ts = TimeSpan.FromMilliseconds(1000);
        t.Wait(ts);
        Debug.Log("returning field status");
        return doesFieldExist;
    } else {
        return false;
    }
}

Эта функция используется для проверки наличия поля в моей базе данных. Цель состоит в том, чтобы использовать задачу для извлечения данных в виде DataSnapshot, перебора этого снимка, чтобы увидеть, существует ли поле, и возврата логического значения в зависимости от результата. Моя проблема в том, что «возвращение статуса поля» отлаживается до того, как «поле существует / не существует». Почему это? Я предполагаю, что это потому, что задачи работают асинхронно и требуется слишком много времени для завершения sh, поэтому остальная часть кода выполняется до того, как это будет выполнено. Как я могу дождаться завершения задачи, прежде чем продолжить работу с каким-либо другим кодом? 1006 *

private async Task<bool> CheckIfFieldExists(string toSearch, string type) {
    if (type == "username") {
        DataSnapshot snap = await playerDataDB.Child("Player").Child(toSearch).GetValueAsync();
        if (snap.Exists) {
            return true;
        }
        else {
            return false;
        }
    } else if (type == "email") {
        DataSnapshot snap = await userAccountDB.Child("Users").Child(toSearch.Remove(toSearch.IndexOf("@"))).Child("email").GetValueAsync();
        if (snap.Exists) { 
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

Помните, что если ваше намерение сравнивает задачу, возвращенную с другим bool, вам необходимо сделать включающий метод asyn c, чтобы вы могли ожидать параметр if-statement. Без этого он не будет компилироваться, так как Task! = Bool.

Ответы [ 2 ]

2 голосов
/ 05 мая 2020

Вы все совершенно неправильно поняли. Не стоит ждать, пока задача закончится. Вы должны использовать «мощь» async / await.

Я настоятельно рекомендую вам прочитать больше об async / await, особенно об async / await на всем пути.

https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

Код после изменения будет:

private async Task<bool> CheckIfFieldExists(string toSearch, string type)
{
    if (type == "username")
    {
        var snap = await playerDataDB.Child("Player").Child(toSearch).GetValueAsync();
        return snap.Exists;
    }
    else
    {
        return false;
    }
}

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

Но я больше ничего не знаю о варианте использования, поэтому я не говорю, что это не нужно.

И еще одна информация о TimeSpan в Wait. Это только для того, чтобы указать, как долго вы хотите ждать задачу. Но как уже было сказано, это необязательно. Конечно, без него - рискуете попасть в тупиковую ситуацию. Так что рекомендуется все-таки ввести некоторый тайм-аут (и обработать его)

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

Это правда, что он использует задачи внизу (и конечный автомат), но использование async / await обычно должно быть простым и «без» задач. Если честно, в этом и был весь смысл их создания.

1 голос
/ 05 мая 2020

Как я могу дождаться завершения задачи, прежде чем продолжить работу с другим кодом?

Это может показаться немного прямолинейным, но вы можете просто удалить тайм-аут:

       TimeSpan ts = TimeSpan.FromMilliseconds(1000);
        t.Wait(ts);

на

t.Wait();

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

Edit:

Я сделал небольшой образец, который демонстрирует то же самое и работает под net47. Возможно, unity обрабатывает asyn c по-разному?

    public static void Main()
    {
        Console.WriteLine("start");
        Task contT = CallbackFunction().ContinueWith(task => {
            Console.WriteLine("First task completed");
            Task.Delay(1000).Wait();
            Console.WriteLine("Returning continuation");
        });

        Console.WriteLine("Waiting");
        contT.Wait();
        Console.WriteLine("All done");
    }

    public async static Task<string> CallbackFunction()
    {
        Console.WriteLine("Before Task.Delay");

        await Task.Delay(1000);

        Console.WriteLine("After Task.Delay - returning");

        return "Photograph";
    }

see: https://dotnetfiddle.net/vKio38

EDIT2:

Даже бросание кода операции в dotnetfiddle показывает, что образец должен работать:

https://dotnetfiddle.net/xa6lCv

вывод:

Before Task.Delay
After Task.Delay - returning
field exists
returning field status
True
...