2013-11-27 113 views
0

假設您擁有一個擁有同步API的第三方庫。自然地,嘗試以異步方式使用它會產生不希望的結果,因爲在嘗試以「並行」方式執行多個事件時,您會遇到阻塞。Node.js同步庫代碼阻止異步執行

是否有任何常見模式允許我們以異步方式使用這樣的庫?

考慮下面的例子(使用async庫從NPM爲了簡潔):

var async = require('async'); 

function ts() { 
    return new Date().getTime(); 
} 

var startTs = ts(); 

process.on('exit', function() { 
    console.log('Total Time: ~' + (ts() - startTs) + ' ms'); 
}); 

// This is a dummy function that simulates some 3rd-party synchronous code. 
function vendorSyncCode() { 
    var future = ts() + 50; // ~50 ms in the future. 

    while(ts() <= future) {} // Spin to simulate blocking work. 
} 

// My code that handles the workload and uses `vendorSyncCode`. 
function myTaskRunner(task, callback) { 
    // Do async stuff with `task`... 

    vendorSyncCode(task); 

    // Do more async stuff... 

    callback(); 
} 

// Dummy workload. 
var work = (function() { 
    var result = []; 

    for(var i = 0; i < 100; ++i) result.push(i); 

    return result; 
})(); 

// Problem: 
// ------- 
// The following two calls will take roughly the same amount of time to complete. 
// In this case, ~6 seconds each. 

async.each(work, myTaskRunner, function(err) {}); 

async.eachLimit(work, 10, myTaskRunner, function(err) {}); 

// Desired: 
// -------- 
// The latter call with 10 "workers" should complete roughly an order of magnitude 
// faster than the former. 

是叉/加入或產卵工作進程手動我唯一的選擇嗎?

回答

0

是的,這是您唯一的選擇。

如果你需要使用50ms的cpu時間做一些事情,並且需要做10次,那麼你需要500ms的cpu時間才能做到。如果您希望在小於500毫秒的掛鐘時間內完成此操作,則需要使用更多的cpus。這意味着多個節點實例(或者將工作推出到線程池的C++插件)。如何獲取多個實例取決於您的應用程序strucuture,使用child_process.send()提供工作的孩子是一種方式,使用集羣運行多個服務器是另一種方式。打破你的服務器是另一種方式。說它是一個圖像存儲應用程序,並且大多數處理請求的速度都很快,除非有人要求將圖像轉換爲另一種格式,並且這是cpu密集型的。您可以將圖像處理部分推入不同的應用程序,並通過REST API訪問它,從而使主應用程序服務器響應。

如果您不擔心需要50ms的cpu來執行請求,但是您擔心的是您無法交叉處理其他請求和處理cpu密集請求,那麼您可能會破壞處理成小塊,並使用setInterval()安排下一個塊。雖然這通常是一個可怕的黑客。更好地重構應用程序。