c#async等待行为不符合预期

时间:2015-08-11 15:12:35

标签: c# sqlite asynchronous async-await

我有c#项目,基本上由以下3个类组成。它应该异步读取本地数据库(sqlite)并继续主进程。虽然它不会抛出任何错误,也不会执行db读取。它只执行主进程while(true) {"Doing Stuff on the Main Thread..."}中包含的无限循环。似乎主线程没有等待异步进程。提前致谢。

class DatabaseAccessor
{
    static void Main(string[] args)
    { 
        var inq = new InquireDatabaseAsync();
        inq.DoWork();

        while (true)
        {
            Console.WriteLine("Doing Stuff on the Main Thread...");
        }
    }      
}

public class InquireDatabaseAsync
{
    public async Task DoWork()
    {
        await Task.Run(() =>
        {
            LongRunningOperation();
        });
    }

    private static async Task LongRunningOperation()
    {
        Data_connection2 dbobject = new Data_connection2();
        SQLiteConnection m_dbConnection = new SQLiteConnection();
        m_dbConnection.ConnectionString = dbobject.datalocation2();
        m_dbConnection.Open();

        string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
        SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);
        var instruct = await ExecuteLoopTaskAsync(SQLcommand);
    }

    public async static Task<string> ExecuteLoopTaskAsync(SQLiteCommand sqlCommand)
    {          
        while (true)
        {
            System.Threading.Thread.Sleep(1000);
            var reader = sqlCommand.ExecuteReader();
            while (reader.Read())
                Console.WriteLine("Id: " + reader["Id"] + "\tInstruction: " + reader["Instruction"] + "\tCellular: " + reader["Cellular"] + "\tTimestamp: " + reader["Timestamp"]);
        }
        return "Finished...";
    }
}

class Data_connection2
{
    public string datalocation2()
    {
        String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        return "Data Source=" + dir + "\\database9.sqlite";
    }
}

4 个答案:

答案 0 :(得分:3)

此行返回Task

inq.DoWork();

但是Task对象没有做过任何事情。因此它以异步方式启动任务,消费代码不会阻塞它。如果你想阻止它(在这种情况下你可能会这样做),你可以等待任务:

inq.DoWork().Wait();

虽然内部工作可能比我能解释的更复杂(或者我此时完全掌握),但有效应具有与使用时相同的观察行为:

await inq.DoWork();

但由于封闭方法不是async,因此您无法使用该语法。

基本上考虑事物应该是&#34;一直异步的范式&#34;。这意味着,在任何给定的异步调用堆栈的顶层,应该存在管理Task的东西。对于诸如WinForms,WPF,ASP.NET等技术,有内置机制来执行此操作。对于控制台应用程序,您基本上更加简单。 main()方法 是最高级别,需要管理堆栈下面的Tasks

答案 1 :(得分:0)

你可能想做的事情可能是,

static void Main(string[] args)
{
    var enquiry = new InquireDatabaseAsync().DoWork();
    while (!enquiry.IsCompleted)
    {
        Console.WriteLine("Doing Stuff on the Main Thread...");
    }

    // In case there were any exceptions.
    enquiry.Wait();
}      

答案 2 :(得分:0)

虽然DoWork在内部等待任务,但它会立即返回给调用者!因此,如果呼叫者想要在继续​​之前等待任务终止,则必须再次等待。

inq.DoWork().Wait();

答案 3 :(得分:0)

此代码有几个问题。考虑使用以下内容:

using System;
using System.Threading.Tasks;

namespace ConsoleApplication6
{
    class DatabaseAccessor
    {
        static async void Main(string[] args)
        {
            await Task.Run(() =>
            {
                InquireDatabaseAsync.LongRunningOperation();
            });
        }
    }

    public static class InquireDatabaseAsync
    {
        public static void LongRunningOperation()
        {
            Data_connection2 dbobject = new Data_connection2();
            SQLiteConnection m_dbConnection = new SQLiteConnection();
            m_dbConnection.ConnectionString = dbobject.datalocation2();
            m_dbConnection.Open();

            string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
            SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);

            while (true)
            {
                System.Threading.Thread.Sleep(1000);
                var reader = sqlCommand.ExecuteReader();
                while (reader.Read())
                    Console.WriteLine("Id: " + reader["Id"] + "\tInstruction: " + reader["Instruction"] + "\tCellular: " + reader["Cellular"] + "\tTimestamp: " + reader["Timestamp"]);
                break;
            }
            Console.WriteLine("Finished.");
        }
    }

    class Data_connection2
    {
        public string datalocation2()
        {
            String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            return "Data Source=" + dir + "\\database9.sqlite";
        }
    }
}