exchange.Go
多线程异步支持函数,可以把所有支持的函数的操作变成异步并发执行。
exchange.Go(method)
exchange.Go(method, ...args)示例
-
exchange.Go()函数使用范例,判断undefined要用typeof(xx) === "undefined",因为null == undefined在JavaScript里是成立的。javascriptfunction main(){ // 以下四种操作是并发多线程异步执行, 不会耗时, 立即返回的 var a = exchange.Go("GetTicker") var b = exchange.Go("GetDepth") var c = exchange.Go("Buy", 1000, 0.1) var d = exchange.Go("GetRecords", PERIOD_H1) // 调用wait方法等待返回异步获取ticker结果 var ticker = a.wait() // 返回深度, 如果获取失败也是有可能返回null的 var depth = b.wait() // 返回订单号, 限定1秒超时, 超时返回undefined, 此对象可以继续调用wait等待如果上次wait超时 var orderId = c.wait(1000) if(typeof(orderId) == "undefined") { // 超时,重新获取 orderId = c.wait() } var records = d.wait() }pythondef main(): a = exchange.Go("GetTicker") b = exchange.Go("GetDepth") c = exchange.Go("Buy", 1000, 0.1) d = exchange.Go("GetRecords", PERIOD_H1) ticker, ok = a.wait() depth, ok = b.wait() orderId, ok = c.wait(1000) if ok == False: orderId, ok = c.wait() records, ok = d.wait()rustfn main() { // Rust中exchange.Go为类型化写法:用Go::方法token指定并发函数,无参传(),有参传元组 // 以下四种操作是并发多线程异步执行, 不会耗时, 立即返回的 let a = exchange.Go(Go::GetTicker, ()); let b = exchange.Go(Go::GetDepth, ()); // Rust中没有Buy的token,等价于CreateOrder,第一个参数""表示当前交易对 let c = exchange.Go(Go::CreateOrder, ("", "buy", 1000, 0.1)); let d = exchange.Go(Go::GetRecords, ("", PERIOD_H1)); // 参数依次为交易对(""表示当前交易对)、K线周期 // 调用wait方法等待返回异步获取ticker结果,wait(0)阻塞直到并发线程运行完毕(对应JS的无参wait()) let ticker = a.wait(0); // 返回深度, 如果获取失败也是有可能返回Err的 let depth = b.wait(0); // 返回订单号, 限定1秒超时, 超时返回Err, 此对象可以继续调用wait等待如果上次wait超时 // 注意:Err也可能是下单本身失败(超时的错误信息为routine N not finished);下单失败时结果已被取走,再次wait会返回Err(routine N already finished) let mut orderId = c.wait(1000); if orderId.is_err() { // 超时,重新获取 orderId = c.wait(0); } let records = d.wait(0); } -
对已经释放的并发对象,调用其
wait()方法会报错。javascriptfunction main() { var d = exchange.Go("GetRecords", PERIOD_H1) // 等待K线结果 var records = d.wait() // 这里wait了一个已经wait过且结束的异步操作,会抛出异常:routine N already finished var ret = d.wait() }pythondef main(): d = exchange.Go("GetRecords", PERIOD_H1) records, ok = d.wait() ret, ok = d.wait()rustfn main() { // Rust中exchange.Go为类型化写法:用Go::方法token指定并发函数 let d = exchange.Go(Go::GetRecords, ("", PERIOD_H1)); // 参数依次为交易对(""表示当前交易对)、K线周期 // 等待K线结果,wait(0)阻塞直到运行完毕(对应JS的无参wait()) let records = d.wait(0); // 这里wait了一个已经wait过且结束的异步操作,会返回Err(routine N already finished) let ret = d.wait(0); } -
并发获取多个交易所行情。
javascriptfunction main() { while(true) { var beginTS = new Date().getTime() var arrRoutine = [] var arrTicker = [] var arrName = [] for(var i = 0; i < exchanges.length; i++) { arrRoutine.push(exchanges[i].Go("GetTicker")) arrName.push(exchanges[i].GetName()) } for(var i = 0; i < arrRoutine.length; i++) { arrTicker.push(arrRoutine[i].wait()) } var endTS = new Date().getTime() var tbl = { type: "table", title: "行情", cols: ["索引", "名称", "最新成交价"], rows: [] } for(var i = 0; i < arrTicker.length; i++) { tbl.rows.push([i, arrName[i], arrTicker[i].Last]) } LogStatus(_D(), "Total time for concurrent ticker retrieval:", endTS - beginTS, "ms", "\n", "`" + JSON.stringify(tbl) + "`") Sleep(500) } }pythonimport time import json def main(): while True: beginTS = time.time() arrRoutine = [] arrTicker = [] arrName = [] for i in range(len(exchanges)): arrRoutine.append(exchanges[i].Go("GetTicker")) arrName.append(exchanges[i].GetName()) for i in range(len(exchanges)): ticker, ok = arrRoutine[i].wait() arrTicker.append(ticker) endTS = time.time() tbl = { "type": "table", "title": "行情", "cols": ["索引", "名称", "最新成交价"], "rows": [] } for i in range(len(arrTicker)): tbl["rows"].append([i, arrName[i], arrTicker[i]["Last"]]) LogStatus(_D(), "Total time for concurrent ticker retrieval:", endTS - beginTS, "seconds", "\n", "`" + json.dumps(tbl) + "`") Sleep(500)rustfn main() { loop { let beginTS = UnixNano() / 1000000; let mut arrRoutine = Vec::new(); let mut arrTicker = Vec::new(); let mut arrName = Vec::new(); for e in exchanges.iter() { // Rust中exchange.Go为类型化写法,token为Go::GetTicker arrRoutine.push(e.Go(Go::GetTicker, ())); arrName.push(e.GetName()); } // 失败时记None占位,保持与arrName按索引对齐 for r in arrRoutine.iter() { arrTicker.push(r.wait(0).ok()); } let endTS = UnixNano() / 1000000; // Rust无JSON序列化,用format!拼接表格的JSON文本 let mut rows = String::new(); for i in 0..arrTicker.len() { if let Some(ticker) = &arrTicker[i] { if !rows.is_empty() { rows.push(','); } rows += &format!(r#"[{}, "{}", {}]"#, i, arrName[i], ticker.Last); } } let tbl = format!(r#"{{"type": "table", "title": "行情", "cols": ["索引", "名称", "最新成交价"], "rows": [{}]}}"#, rows); LogStatus!(_D(None), "Total time for concurrent ticker retrieval:", endTS - beginTS, "ms", "\n", format!("`{}`", tbl)); Sleep(500); } } -
对
exchange.IO("api", ...)函数并发调用。javascriptfunction main() { /* 使用OKX期货下单接口测试 POST /api/v5/trade/order */ var beginTS = new Date().getTime() var param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"} var ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var id1 = ret1.wait() var id2 = ret2.wait() var id3 = ret3.wait() var endTS = new Date().getTime() Log("id1:", id1) Log("id2:", id2) Log("id3:", id3) Log("Concurrent order time:", endTS - beginTS, "ms") }pythonimport time import json def main(): beginTS = time.time() param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"} ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) id1, ok1 = ret1.wait() id2, ok2 = ret2.wait() id3, ok3 = ret3.wait() endTS = time.time() Log("id1:", id1) Log("id2:", id2) Log("id3:", id3) Log("Concurrent order time:", endTS - beginTS, "seconds")rustfn main() { /* 使用OKX期货下单接口测试 POST /api/v5/trade/order */ let beginTS = UnixNano() / 1000000; // Rust无JSON序列化,直接用原始字符串构造参数 let param = r#"{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}"#; // Rust中exchange.Go为类型化写法,token为Go::IO,参数以元组传入 let ret1 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let ret2 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let ret3 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let id1 = ret1.wait(0); let id2 = ret2.wait(0); let id3 = ret3.wait(0); let endTS = UnixNano() / 1000000; Log!("id1:", id1); Log!("id2:", id2); Log!("id3:", id3); Log!("Concurrent order time:", endTS - beginTS, "ms"); } -
针对自动释放机制的测试
javascriptfunction main() { var counter = 0 var arr = [] // 用于测试持续引用并发的相关变量 var symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"] while (true) { var arrRoutine = [] for (var symbol of symbols) { var r = exchange.Go("GetTicker", symbol) arrRoutine.push(r) // 记录并发对象用于调用 r.wait() 函数获取结果,每一轮循环都清空 // arr.push(r) // 如果使用这句代码,运行时持续引用并发的对象,无法自动释放;未取结果的并发任务达到2000个后,再调用exchange.Go()会报错:too many routine wait, max is 2000 counter++ } // 遍历 arrRoutine 调用 r.wait() LogStatus(_D(), "routine number:", counter) Sleep(50) } }rustfn main() { let mut counter = 0; let mut arr: Vec<TypedRoutine<Go::GetTicker>> = Vec::new(); // 用于测试持续引用并发的相关变量 let symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"]; loop { let mut arrRoutine = Vec::new(); for symbol in symbols { // Rust中exchange.Go为类型化写法,token为Go::GetTicker let r = exchange.Go(Go::GetTicker, (symbol,)); arrRoutine.push(r); // 记录并发对象用于调用 r.wait(0) 函数获取结果,每一轮循环都清空 // arr.push(r); // 如果使用这句代码,运行时持续引用并发的对象,无法自动释放;未取结果的并发任务达到2000个后,再调用exchange.Go()会报错:too many routine wait, max is 2000 counter += 1; } // 遍历 arrRoutine 调用 r.wait(0) LogStatus!(_D(None), "routine number:", counter); Sleep(50); } }
返回值
| 类型 | 描述 |
object | 立即返回一个并发对象,用它的 |
参数
| 名称 | 类型 | 必填 | 描述 |
method | string | 是 | 并发的函数名称,注意该参数是函数名称字符串,并非函数引用。 |
arg | string / number / bool / object / array / function / any | 否 | 并发执行函数的参数,参数 |
参考
备注
该函数只在实盘运行时创建多线程执行任务,回测不支持多线程并发执行任务(回测可用,但是还是顺序执行)。
并发对象wait()方法的超时参数,以及各语言在完成、超时、重复调用时的返回值,见exchange.Go-return。Python中wait()返回(结果, 是否成功)两个值。
虽然系统底层有自动回收机制,但是如果持续引用相关变量,并发任务的结果并不会释放。未取结果的并发任务达到2000个时,再调用exchange.Go()提交新任务会当场报错:"too many routine wait, max is 2000",该任务不会执行。
支持的函数:GetTicker,GetDepth,GetTrades,GetRecords,GetAccount,GetOrders,GetOrder,CancelOrder,Buy,Sell,GetPositions,IO等。这些函数并发调用时都基于当前exchange交易所对象执行。