並行性與執行緒安全¶
一般來說,物件允許多個執行緒的序列化存取:一個執行緒可以進行呼叫,一旦完成,另一個執行緒可以進行呼叫。它們不允許多個執行緒的並行存取。
稍微相關的是從單個執行緒或多個執行緒重疊/並行執行多步驟操作的問題。例如,可以從同一個 AdbcConnection 建立兩個 AdbcStatement 物件
struct AdbcStatement stmt1;
struct AdbcStatement stmt2;
struct ArrowArrayStream out1;
struct ArrowArrayStream out2;
/* Ignoring error handling for brevity */
AdbcStatementNew(&conn, &stmt1, NULL);
AdbcStatementNew(&conn, &stmt2, NULL);
AdbcStatementSetSqlQuery(&stmt1, "SELECT * FROM a", NULL);
AdbcStatementSetSqlQuery(&stmt2, "SELECT * FROM b", NULL);
AdbcStatementExecuteQuery(&stmt1, &out1, NULL, NULL);
AdbcStatementExecuteQuery(&stmt2, &out2, NULL, NULL);
/* What happens to the result set of stmt1? */
如果客戶端應用程式在 stmt1
上呼叫 AdbcStatementExecuteQuery()
,然後在 stmt2
上呼叫,而沒有讀取 stmt1
的結果集,會發生什麼事?一些現有的客戶端函式庫/協議,例如 libpq,不支援從單個連線並行執行查詢。因此,驅動程式必須 1) 在第一次 Execute
期間將所有結果緩衝到記憶體中(或以其他方式允許程式繼續讀取第一個結果集),2) 在第二次 Execute
時發出錯誤,或 3) 在第二次 Execute
時使第一個語句的結果集無效。
在這種情況下,ADBC 允許驅動程式選擇 1) 或 2)。如果可能且合理,驅動程式應允許並行執行,無論是因為底層協議是為此設計的,還是通過緩衝結果集。但是,如果無法支援,則允許驅動程式報錯。
另一個用例是擁有單個語句,但多次執行它並並行讀取結果集。例如,客戶端可能希望使用預備語句來執行此操作
/* Ignoring error handling for brevity */
struct AdbcStatement stmt;
AdbcStatementNew(&conn, &stmt, NULL);
AdbcStatementSetSqlQuery(&stmt, "SELECT * FROM a WHERE foo > ?", NULL);
AdbcStatementPrepare(&stmt, NULL);
struct ArrowArrayStream stream;
AdbcStatementBind(&stmt, &array1, &schema, NULL);
AdbcStatementExecuteQuery(&stmt, &stream, NULL, NULL);
/* Spawn a thread to process `stream` */
struct ArrowArrayStream stream2;
AdbcStatementBind(&stmt, &array2, &schema, NULL);
AdbcStatementExecuteQuery(&stmt, &stream2, NULL, NULL);
/* What happens to `stream` here? */
ADBC 選擇不允許這樣做(具體來說:第二次呼叫 Execute
必須使第一次呼叫的結果集無效),這與現有的 API 一致,這些 API 通常不支援以這種方式「重疊」使用單個預備語句。