我正在使用Goliath(這是由eventmachine供電)和postgres寶石pg
,目前我使用封鎖的方式pg寶石:conn.exec('SELECT * FROM products')
(例如),我想知道是否有更好的方式連接到postgres數據庫?使用postgresql創業板異步
回答
pg
庫提供對PostgreSQL的異步API的全面支持。我已經添加了如何用它來samples/
目錄an example:
#!/usr/bin/env ruby
require 'pg'
# This is a example of how to use the asynchronous API to query the
# server without blocking other threads. It's intentionally low-level;
# if you hooked up the PGconn#socket to some kind of reactor, you
# could make this much nicer.
TIMEOUT = 5.0 # seconds to wait for an async operation to complete
CONN_OPTS = {
:host => 'localhost',
:dbname => 'test',
:user => 'jrandom',
:password => 'banks!stealUR$',
}
# Print 'x' continuously to demonstrate that other threads aren't
# blocked while waiting for the connection, for the query to be sent,
# for results, etc. You might want to sleep inside the loop or
# comment this out entirely for cleaner output.
progress_thread = Thread.new { loop { print 'x' } }
# Output progress messages
def output_progress(msg)
puts "\n>>> #{msg}\n"
end
# Start the connection
output_progress "Starting connection..."
conn = PGconn.connect_start(CONN_OPTS) or
abort "Unable to create a new connection!"
abort "Connection failed: %s" % [ conn.error_message ] if
conn.status == PGconn::CONNECTION_BAD
# Now grab a reference to the underlying socket so we know when the
# connection is established
socket = IO.for_fd(conn.socket)
# Track the progress of the connection, waiting for the socket to
# become readable/writable before polling it
poll_status = PGconn::PGRES_POLLING_WRITING
until poll_status == PGconn::PGRES_POLLING_OK ||
poll_status == PGconn::PGRES_POLLING_FAILED
# If the socket needs to read, wait 'til it becomes readable to
# poll again
case poll_status
when PGconn::PGRES_POLLING_READING
output_progress " waiting for socket to become readable"
select([socket], nil, nil, TIMEOUT) or
raise "Asynchronous connection timed out!"
# ...and the same for when the socket needs to write
when PGconn::PGRES_POLLING_WRITING
output_progress " waiting for socket to become writable"
select(nil, [socket], nil, TIMEOUT) or
raise "Asynchronous connection timed out!"
end
# Output a status message about the progress
case conn.status
when PGconn::CONNECTION_STARTED
output_progress " waiting for connection to be made."
when PGconn::CONNECTION_MADE
output_progress " connection OK; waiting to send."
when PGconn::CONNECTION_AWAITING_RESPONSE
output_progress " waiting for a response from the server."
when PGconn::CONNECTION_AUTH_OK
output_progress " received authentication; waiting for " +
"backend start-up to finish."
when PGconn::CONNECTION_SSL_STARTUP
output_progress " negotiating SSL encryption."
when PGconn::CONNECTION_SETENV
output_progress " negotiating environment-driven " +
"parameter settings."
end
# Check to see if it's finished or failed yet
poll_status = conn.connect_poll
end
abort "Connect failed: %s" % [ conn.error_message ] unless
conn.status == PGconn::CONNECTION_OK
output_progress "Sending query"
conn.send_query("SELECT * FROM pg_stat_activity")
# Fetch results until there aren't any more
loop do
output_progress " waiting for a response"
# Buffer any incoming data on the socket until a full result
# is ready.
conn.consume_input
while conn.is_busy
select([socket], nil, nil, TIMEOUT) or
raise "Timeout waiting for query response."
conn.consume_input
end
# Fetch the next result. If there isn't one, the query is
# finished
result = conn.get_result or break
puts "\n\nQuery result:\n%p\n" % [ result.values ]
end
output_progress "Done."
conn.finish
if defined?(progress_thread)
progress_thread.kill
progress_thread.join
end
我建議你讀的PQconnectStart功能和PostgreSQL的手冊Asynchronous Command Processing部分中的文檔,然後比較,與上面的樣品。
我之前沒有使用過EventMachine,但是如果它允許你註冊一個套接字並在它變得可讀寫時進行回調,那麼我認爲將數據庫調用集成到它中會相當容易。
我一直有意使用Ilya Grigorik's article on using Fibers to clean up evented code中的想法來使異步API更易於使用,但這是一個辦法。我確實有a ticket open跟蹤它,如果你有興趣/動機自己動手。
我不再對Pg非常熟悉,但我還沒有聽說任何流行的數據庫都可以異步連接。因此,在查詢期間,您仍然需要維護與數據庫的連接。因此,您仍然需要阻止某些位置的堆棧。
根據您的應用程序,您可能已經在儘可能地做到最好。
但是,當你正在處理某種輪詢應用程序(在相同的客戶端在短時間內發送大量請求),並且獲得響應更加重要,即使它是空的,那麼你可以寫一個紅寶石Fiber
或者滔滔不絕的線程或流程,這些線程或流程長期存在並代理對數據庫的查詢並緩存結果。
例如:來自客戶端A的請求進入。Goliath應用程序使用一些唯一ID處理對數據庫進程的查詢,並用'沒有數據'來響應查詢。數據庫進程完成查詢並將結果保存到帶有ID的緩存中。當來自同一客戶端的下一個請求進入時,Goliath發現它已經有查詢結果在等待,從緩存中刪除結果並響應客戶端。同時,它會使用數據庫進程安排下一個查詢,以便儘早完成。如果下一個請求在最後一個請求完成之前進入,則不會安排新的查詢(不會增加查詢)。
通過這種方式,您的響應速度非常快且無阻塞,同時仍然能夠儘快從DB中提供新數據。當然,它們可能與實際數據有些不同步,但是,根據應用程序的不同,這可能不成問題。
這個想法是使用一個異步適配器到數據庫(Postgresql)連同一個已經連接的Web服務器(Goliath)來獲得性能。 Mike Perham去年爲Rails 2.3寫了一個PG activerecord adaptor。也許你可以使用它。
又如,Ilya Grigorik發佈了異步Rails堆棧的this demo。在這種情況下,偶數服務器是Thin,而數據庫是Mysql。安裝演示程序並嘗試使用和不使用EM感知驅動程序的基準測試。差異很大。
我想找到一個異步適配器postgresql,但我找不到任何將在其上工作(沒有activerecord例如)和一個這是定期更新 – errorhandler 2011-05-06 06:33:07
恐怕你是在曲線的前面過多,以指望在這一點上的任何事情。 Perham很好,他正在迴應有關在Rails 3中工作的幫助請求。以下是上述適配器中postresql連接例程的鏈接,以防萬一您錯過了它:https://github.com/mperham/ em_postgresql/blob/master/lib/postgres_connection.rb – seph 2011-05-07 14:22:38
是的,你可以從goliath以非阻塞的方式訪問postgres。我有同樣的需要,並放在一起這個概念證明:https://github.com/levicook/goliath-postgres-spike
- 1. Wicket異步作業
- 2. 異步TaskManager處理作業/步異常
- 3. PostgreSQL與epoll_wait異步連接
- 4. Django PostgreSQL異步提交
- 5. PostgreSQL的同步和異步複製
- 6. Laravel作業查詢異步/同步?
- 7. 使用C#異步作業執行和作業狀態管理使用C#
- 8. 創業板古藪
- 9. 使用異步
- 10. 使用php創建異步數據庫
- 11. 使用CodeMemberMethod創建異步方法
- 12. 使用Task.FromResult創建異步操作
- 13. 以異步方式異步創建BitmapFrame
- 14. Postpost PostgreSQL與PostgreSQL PostSharp 4.0的最新版本使用異步方法
- 15. 異步編程使用異步/等待
- 16. 同步使用異步值
- 17. 使異步調用同步
- 18. 使異步調用同步
- 19. 在node.js/express中異步關閉異步作業
- 20. 更新ASP.NET面板異步
- 21. Backbone.Marionette模板異步加載
- 22. 異步更新面板_
- 23. 使用異步方法在企業制度
- 24. WebAPI:在業務邏輯中使用異步方法
- 25. 如何使用Insights API異步作業下載Facebook報告?
- 26. 使用FREAD()異步
- 27. 使用異步管
- 28. 異步使用AppDomain.DoCallBack()
- 29. 軌創業板安裝PG
- 30. 如何通過創業板
感謝Michael,這非常有幫助。我在這裏找到了一個以相對乾淨的方式將它與EventMachine reactor連接起來的gem:https://github.com/jtoy/em-postgres – Levi 2012-03-15 21:40:43