2014-02-07 50 views
0

我正在嘗試將dart與sqlite結合使用,此項目爲dart-sqlite如何將dart-sqlite代碼從同步樣式更改爲異步?

但我發現一個問題:它提供的API是同步樣式。該代碼將看起來像:

// Iterating over a result set 
var count = c.execute("SELECT * FROM posts LIMIT 10", callback: (row) { 
    print("${row.title}: ${row.body}"); 
}); 
print("Showing ${count} posts."); 

有了這樣的代碼,我不能用飛鏢未來的支持,代碼將在SQL操作會阻止。

我不知道如何將代碼更改爲異步樣式?你可以看到它定義了一些native功能在這裏:https://github.com/sam-mccall/dart-sqlite/blob/master/lib/sqlite.dart#L238

_prepare(db, query, statementObject) native 'PrepareStatement'; 
_reset(statement) native 'Reset'; 
_bind(statement, params) native 'Bind'; 
_column_info(statement) native 'ColumnInfo'; 
_step(statement) native 'Step'; 
_closeStatement(statement) native 'CloseStatement'; 
_new(path) native 'New'; 
_close(handle) native 'Close'; 
_version() native 'Version'; 

的本地函數映射到一些C++函數在這裏:https://github.com/sam-mccall/dart-sqlite/blob/master/src/dart_sqlite.cc

是否有可能改變異步?如果可能的話,我該怎麼辦?

如果不能,那我不得不重寫它,我必須重寫所有的:

  1. 鏢文件
  2. 的C++封裝文件
  3. 實際的sqlite的驅動程序

更新:

感謝@ GregLowe的評論,Dart的Completer可以將回調風格轉換爲未來風格,這可以讓我使用Dart的doSomething().then(...)而不是傳遞迴調函數。

但是看完飛鏢sqlite的根源後,我意識到,在飛鏢的SQLite的實施,callback不是基於事件的:

int execute([params = const [], bool callback(Row)]) { 
    _checkOpen(); 
    _reset(_statement); 
    if (params.length > 0) _bind(_statement, params); 
    var result; 
    int count = 0; 
    var info = null; 
    while ((result = _step(_statement)) is! int) { 
    count++; 
    if (info == null) info = new _ResultInfo(_column_info(_statement)); 
    if (callback != null && callback(new Row._internal(count - 1, info, result)) == true) { 
     result = count; 
     break; 
    } 
    } 
    // If update affected no rows, count == result == 0 
    return (count == 0) ? result : count; 
} 

即使我用Completer,它贏得了」提高表現。我想我可能必須重寫C++代碼才能使其基於事件。

+0

此代碼已過時,因爲寫在2年前。所以,你的問題仍然不是真實的。除此之外如果你不想自己重寫它(dart-sqlite)。 – mezoni

+0

我修改了它可以正確運行的代碼,但我不喜歡代碼風格。所以我必須重寫代碼,如果我想要異步風格?我必須重寫驅動程序部分(c/C++)以支持異步嗎? – Freewind

+1

你應該可以編寫一個包裝器而不需要觸摸C++。看看如何使用dart中的Completer類:異步。基本上你需要創建一個Completer,立即返回Completer.future,然後從現有的回調中調用Completer.complete(row)。 –

回答

1

你應該可以編寫一個包裝而不用觸碰C++。看看如何使用dart中的Completer類:異步。基本上你需要創建一個Completer,立即返回Completer.future,然後從現有的回調中調用Completer.complete(row)。

回覆:更新。你見過這article,特別是關於異步擴展的位?即,如果C++ API是同步的,則可以在單獨的線程中運行它,並使用消息傳遞與它通信。這可能是一種方法。

1

你遇到的最大問題是SQLite是一個嵌入式數據庫;爲了處理您的查詢並提供您的結果,必須在您的過程中執行計算(和I/O)。更重要的是,爲了使事務處理系統正常工作,它可能需要連接到thread that created it,或者您需要以串行模式運行(性能受到影響)。

因爲這些都是相當嚴格的約束,所以將事物切換到異步操作模式的計劃不太可能順利進行,除非使用多個線程。由於使用多個連接會使事情變得複雜(因爲你不能在它們之間共享某些東西,比如TEMP TABLE s),我們考慮使用單個串行連接;所有活動都將在數據庫級別進行序列化,但是對於不使用數據庫的應用程序而言,它會很好。在C++級別,你會談論從另一個線程調用execute,然後將消息發送回調用者線程以指示每行和完成。 但是,當你這樣做時,你會受到真正的打擊;特別是,您承諾一次只執行一個查詢,因爲當您一次開始使用兩個連接並且DB使用一個連接強制對您進行序列化時,該技術會遇到語義影響的重大問題。

通過管理工作線程和線程間通信,將同步 - 異步耦合置於Dart級別,可能會更簡單。這將讓你避免不必要更改C++代碼。我不太瞭解Dart,能夠在那裏提供很多建議。

我自己,我只是堅持同步連接處理,以便我可以使我的應用程序更有用地使用多線程模式。我將會受到語義的衝擊,併爲每個線程提供自己的連接(可能是懶惰地分配的),這樣整體速度會更好,但我確實來自一個將線程視爲相對重量級資源的編程社區,所以要做到這一點你會。 (重線程可以做的事情,減少他們需要的鎖的數量,它是沒有意義的嘗試使用輕線程;這是關於管理費用。)