Các ứng dụng của hàm _Thread trong thiết kế chính sách JavaScript

Tác giả:Giấc mơ nhỏ, Tạo: 2023-07-04 16:35:42, Cập nhật: 2023-09-18 19:32:51

img

Các ứng dụng của hàm _Thread trong thiết kế chính sách JavaScript

Trong thiết kế chính sách FMZ ban đầu, chỉ sử dụng các hoạt động đồng bộ không đồng bộ nếu cần thiết.exchange.Go()Các chức năng để thực hiện đồng bộ của giao diện bọc FMZ, không thể thực hiện một số hoạt động tùy chỉnh (công việc) cùng một lúc. Mặc dù thiết kế này giúp chương trình chính sách được thực hiện hiệu quả hơn nhiều, nhưng đối với các học sinh có kinh nghiệm thiết kế đồng bộ trong ngôn ngữ lập trình gốc, cảm giác chung là rất khó khăn.

Ngay cả những học sinh mới sử dụng giao dịch định lượng đầu vào FMZ cũng không hiểu.exchange.Go()Sử dụng hàm, sử dụngexchange.Go()Có vẻ như vẫn còn một câu lệnh thực thi trong mã được thực thi theo thứ tự.__Thread()Việc sử dụng các hàm chuỗi v.v. là không đồng bộ với việc thiết kế các quy trình chính sách.

Một, thiết kế đồng thời đơn giản

Nếu chúng ta muốn chạy một hàm tùy chỉnh mà chúng ta đã viết cùng một lúc với một hàm chủ chính sách, chúng ta có thể sử dụng một thiết kế tương tự như sau.GetTickerAsync(), viết các chức năng cụ thể của hàm này.whileCác giao diện API của FMZ liên tục được gọi trong vòng lặp:GetTicker()Những người tham gia vào cuộc họp này đã được mời đến tham gia.

Sau đó sử dụng lại.__threadSetData(0, "ticker", t)Nó viết một dữ liệu vào một chuỗi chủ, tên dữ liệu làtickerGiá trị dữ liệu là:tCó nghĩa làGetTicker()Các giá trị được trả về là:

__threadSetData(0, "ticker", t)

Sau khi thiết kế các hàm tùy chỉnh để thực hiện song song với các chuỗi, chúng ta có thể viếtmain()Và chúng ta có thể làm điều đó.main()Chúng ta bắt đầu với:

__Thread(GetTickerAsync, 0)   // GetTickerAsync为需要并发执行的自定义函数,0为这个传入GetTickerAsync函数的参数

Tạo một chuỗi nối liền và nó bắt đầu thực hiện.GetTickerAsync()Chức năng.main()Các hàm bắt đầu tự thực hiệnwhileChuyển vòng, tiếp nhận trong vòngGetTickerAsync()Dữ liệu được cập nhật của hàm sau đó in:

var t = __threadGetData(0, "ticker")
Log(t)

Ví dụ về mã đầy đủ:

function GetTickerAsync(index) {
    while (true) {
        var t = exchanges[index].GetTicker()
        __threadSetData(0, "ticker", t)
        Sleep(500)
    }
}

function main() {
    __Thread(GetTickerAsync, 0)

    while(true) {
        var t = __threadGetData(0, "ticker")
        Log(t)
        Sleep(1000)
    }
}

Thử nghiệm chạy trên đĩa thật:

img

Đây là một trong những thiết kế ứng dụng đơn giản nhất, sau đây chúng ta sẽ xem một số thiết kế nhu cầu khác.

2, đồng thời phát hành thiết kế đơn lẻ

Một hàm có thể được thiết kế để tạo ra 10 luồng cùng một lúc, mỗi luồng thực hiện một hàm điều hành dưới.main()Thiết kế một hàmwhileCác chỉ thị tương tác xung quanh, phát hiện chính sách.placeMultipleOrdersChúng ta sẽ gọi hàm này.testPlaceMultipleOrders()

if (cmd == "placeMultipleOrders") {
    // ...
}

Thêm thiết kế tương tác chính sách trên trang chỉnh sửa chính sách, đặt một nút, lệnh là: placeMultipleOrders

img

Ví dụ về mã đầy đủ:

function placeOrder(exIndex, type, price, amount) {
    var id = null 
    if (type == "Buy") {
        id = exchanges[exIndex].Buy(price, amount)
    } else if (type == "Sell") {
        id = exchanges[exIndex].Sell(price, amount)
    } else {
        throw "type error! type:" + type
    }
}

function testPlaceMultipleOrders(index, beginPrice, endPrice, step, type, amount) {
    Log("beginPrice:", beginPrice, ", endPrice:", endPrice, ", step:", step, ", type:", type, ", amount:", amount)
    var tids = []
    for (var p = beginPrice; p <= endPrice; p += step) {
        var tid = __Thread(placeOrder, index, type, p, amount)
        tids.push(tid)
        Sleep(10)
    }
    Sleep(1000)
    for (var i = 0; i < tids.length; i++) {
        __threadTerminate(tids[i])
    }
}

function main() {
    while(true) {
        LogStatus(_D())
        var cmd = GetCommand()
        if (cmd) {
            if (cmd == "placeMultipleOrders") {
                var t = _C(exchange.GetTicker)
                var beginPrice = t.Last * 0.8
                var endPrice = t.Last * 0.9
                var step = t.Last * 0.01
                testPlaceMultipleOrders(0, beginPrice, endPrice, step, "Buy", 0.01)
                var orders = exchange.GetOrders()
                for (var i = 0; i < orders.length; i++) {
                    Log(orders[i])
                }
            }
        }
        Sleep(1000)
    }
}
  • Kiểm tra bằng cách sử dụng bảng xếp hạng, tăng dần từ 80% ~ 90% giá hiện tại, sử dụng thử nghiệm môi trường đĩa tương tự, bấm nút tương tác kích hoạt kiểm tra đặt hàng:

    img

  • Sau khi nhấp vào nút "placeMultipleOrders", bạn sẽ thấy thông báo:

    img

  • Các hoạt động này sẽ được hiển thị trên nhật ký chính sách:

    img

3, Tạo kết nối WebSocket trong các chức năng thực thi chuỗi đồng thời

Yêu cầu này được đưa ra bởi một người dùng FMZ, mong muốn có một ví dụ đơn giản để chứng minh cách sử dụng trong các chuỗi song song.WebSocketVà chúng tôi sẽ thiết kế một hệ thống kết nối, và thiết kế cách để truyền dữ liệu đến các đường dây chính.main()Chức năng.

Trong thực tế, rất đơn giản, và tạo các chuỗi song song tương tự như trong ví dụ trước; nhưng chỉ sử dụng giao tiếp giữa các chuỗi.__threadPeekMessage()Chức năng và__threadPostMessage()Chức năng. Ví dụ như gọi giao diện API WebSocket của sàn giao dịch Bitcoin, trong thiết kế chúng ta cũng cần chú ý đến các thao tác đóng kết nối WebSocket, ví dụ sau đây cũng cho thấy cách thông báo cho một chuỗi song song và khiến nó dừng lại.

Ví dụ về mã đầy đủ:

var tid = null 

function createWS() {
    // wss://stream.binance.com:9443/ws/<streamName> , <symbol>@ticker
    
    var stream = "wss://stream.binance.com:9443/ws/btcusdt@ticker"    
    var ws = Dial(stream)
    Log("创建WS连接:", stream)
    
    while (true) {
        var data = ws.read()
        if (data) {            
            __threadPostMessage(0, data)
        }
        Log("接收到WS链接推送的数据,data:", data)
        
        // __threadPeekMessage 超时参数设置-1,不阻塞
        var msg = __threadPeekMessage(-1)
        if (msg) {
            if (msg == "stop") {
                Log("并发线程Id:", __threadId(), "接收到stop指令")
                break
            }
        }
    }

    Log("并发线程执行完毕,关闭ws连接")
    ws.close()
}

function main() {
    tid = __Thread(createWS)
    Log("创建并发线程,线程Id:", tid)

    while(true) {
        // __threadPeekMessage 的超时参数设置为0,阻塞等待数据
        var data = __threadPeekMessage(0)
        Log("接收到并发线程", ", Id:", tid, ", 发送的数据,data:", data, "#FF0000")
        
        var tbl = {
            type : "table", 
            title : "<symbol>@ticker频道推送消息",
            cols : ["事件类型", "事件时间", "交易对", "24小时价格变化", "24小时价格变化百分比", "平均价格", "最新成交价格", "24小时内成交量", "24小时内成交额"],
            rows : []
        }

        try {
            data = JSON.parse(data)
            tbl.rows.push([data.e, _D(data.E), data.s, data.p, data.P, data.w, data.c, data.v, data.q])
        } catch (e) {
            Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
        }
        LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
    }
}

function onexit() {
    Log("扫尾函数,向Id为", tid, "的并发线程发送stop指令")
    __threadPostMessage(tid, "stop")
    Log("等待Id为", tid, "的并发线程停止")
    __threadJoin(tid)
    Log("扫尾函数执行完毕")
}

Thử nghiệm chạy trên đĩa thật:

img

Bạn có thể thấymain()Chức năng này liên tục nhận dữ liệu thị trường từ các kết nối WebSocket được tạo ra bởi các chuỗi đồng thời.

Khi ngừng chính sách thực, hàm quét đuôi bắt đầu hoạt động:

img


Có liên quan

Thêm nữa

Sparta chơi theo định lượngVí dụ cuối cùng, nếu có rất nhiều ws thread và bạn đã đăng ký nhiều topic, thì giao tiếp giữa các thread, cách nào hiệu quả hơn là sử dụng get/set hoặc peek/post?

Sparta chơi theo định lượngThực hiện hạ tầng của các biến chia sẻ giữa các chuỗi là không hỗ trợ các biến tham chiếu, phải được đặt lại mỗi lần cập nhật, điều này rất kém hiệu quả.

Giấc mơ nhỏCó thể là hai cách này không có gì khác nhau.