Aplikasi fungsi _Thread dalam reka bentuk dasar JavaScript

Penulis:Mimpi kecil, Dicipta: 2023-07-04 16:35:42, Dikemas kini: 2023-09-18 19:32:51

img

Aplikasi fungsi _Thread dalam reka bentuk dasar JavaScript

Dalam reka bentuk dasar FMZ asal, operasi serentak tidak serentak hanya boleh digunakan jika diperlukanexchange.Go()Fungsi untuk mencapai penyegerakan antara muka FMZ tidak dapat menjalankan beberapa operasi khusus (fungsi) secara serentak. Walaupun reka bentuk ini meningkatkan kecekapan pelaksanaan program dasar, tetapi para pelajar yang mempunyai pengalaman reka bentuk serentak dalam bahasa pemrograman asli tidak terbiasa dengan perasaan umum.

Malah rakan sekelas baru yang menggunakan FMZ untuk melakukan transaksi kuantitatif tidak faham.exchange.Go()Penggunaan fungsi, penggunaanexchange.Go()Ia masih kelihatan seperti satu perintah pelaksanaan dalam kod yang dijalankan secara berurutan. Jadi, dalam artikel ini, kita akan meneroka ciri-ciri baru dalam FMZ:__Thread()Penggunaan fungsi siri dan lain-lain tidak selaras dengan reka bentuk prosedur strategi.

1. Reka bentuk serentak yang mudah

Jika kita ingin membuat dasar utama berjalan pada masa yang sama, kita boleh menggunakan reka bentuk seperti berikut.GetTickerAsync(), menulis fungsi tertentu untuk fungsi ini. Fungsi ini menjalankan satu pusingan mati, di manawhileAntara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antara antaraGetTicker()Di sini, anda boleh mendapatkan data mengenai pasaran.

Kemudian digunakan semula.__threadSetData(0, "ticker", t)Ini akan menulis data ke dalam tali utama, nama data yang dipanggiltickerNilai data ialahtMaksudnya,GetTicker()Nilai yang dikembalikan adalah

__threadSetData(0, "ticker", t)

Selepas kita merancang fungsi khusus yang dijalankan secara serentak, kita boleh menulismain()Jadi, jika anda mempunyai kod di dalam fungsi,main()Untuk memulakan fungsi, kita gunakan:

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

Buatlah satu thread yang serentak, dan thread ini mula menjalankanGetTickerAsync()Fungsi. Kemudian.main()Fungsi mula menjalankan sendiri.whilePeredaran, menerima dalam kitaranGetTickerAsync()Data yang dikemas kini oleh fungsi kemudian dicetak:

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

Contoh kod lengkap:

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)
    }
}

Percubaan berjalan pada cakera sebenar:

img

Ini adalah satu reka bentuk aplikasi yang paling mudah, dan kita akan melihat beberapa reka bentuk keperluan yang lain.

2, Rancangan Bersama

Satu fungsi boleh direka untuk mencipta 10 benang pada masa yang sama, dan setiap benang akan menjalankan satu fungsi operasi bawah.main()Buatlah satu fungsi.whilePerintah interaksi pusingan, strategi pengesanan.placeMultipleOrdersJadi, jika anda ingin memanggil fungsi yang sama, anda perlu memanggilnya.testPlaceMultipleOrders()

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

Menambah reka bentuk interaksi dasar pada halaman penyuntingan dasar, menetapkan butang, perintah: placeMultipleOrders

img

Contoh kod lengkap:

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)
    }
}
  • Ujian menggunakan cara hover, meningkat dari harga semasa 80% ~ 90%, menggunakan ujian persekitaran piringan analog, klik butang interaksi untuk mencetuskan ujian hover:

    img

  • Setelah mengklik butang "placeMultipleOrders", mesej akan muncul:

    img

  • Dalam log strategi, anda akan melihat operasi yang disatukan:

    img

3. Membuat sambungan WebSocket dalam fungsi pelaksanaan utas serentak

Permintaan ini dikemukakan oleh pengguna FMZ yang berharap mempunyai contoh mudah untuk menunjukkan bagaimana ia digunakan dalam utas serentakWebSocketPerisian yang digunakan untuk membuat sambungan dan merancang cara untuk menghantar data ke benang utama.main()Fungsi tersebut.

Sebenarnya sangat mudah, dan hampir sama dengan contoh sebelumnya untuk membuat benang serentak; hanya menggunakan komunikasi antara benang.__threadPeekMessage()Fungsi dan__threadPostMessage()Fungsi. Sebagai contoh panggilan antara muka API WebSocket pertukaran Bitcoin, dalam reka bentuk, kita juga perlu memperhatikan operasi untuk menutup sambungan WebSocket, contoh berikut juga menunjukkan bagaimana memberi notis kepada benang serentak untuk menghentikan.

Contoh kod lengkap:

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("扫尾函数执行完毕")
}

Percubaan berjalan pada cakera sebenar:

img

Kita boleh lihatmain()Fungsi ini terus menerima data perdagangan yang diterima oleh sambungan WebSocket yang dicipta oleh benang serentak.

Apabila anda menghentikan dasar pada cakera sebenar, fungsi sweep tail akan mula berfungsi:

img


Berkaitan

Lebih lanjut

Spada bermain kuantitatifContoh terakhir, jika terdapat banyak thread ws dan anda mempunyai banyak tema yang terdaftar, maka mana yang lebih baik untuk menggunakan kaedah get/set atau peek/post untuk komunikasi antara thread?

Spada bermain kuantitatifImplementasi asas pembahagian pembolehubah antara benang adalah tidak menyokong pembolehubah rujukan, yang harus disetel semula setiap kali ia dikemas kini, yang sangat tidak cekap.

Mimpi kecilWalaupun tidak ada perbezaan antara kedua-dua cara ini, ia boleh dilakukan.