I've got a couple of questions involving creating async wrappers around expensive synchronous operations.
The expensive sync code performs cryptographic operations, so for obvious reasons I want these operations running in a separate thread so as not to block the main thread's async operations. Currently, to perform a crypto operation, I'm:
Testing the code has yielded confusing results. The normal, synchronous implementation works without problems. The async wrappers around the sync implementation fail at a random point each time. When they fail, they produce no stacktrace, just the message:
Error: execution of an external program failed: '...\test.exe'
tools.nim(36) doCmd
Error: Execution failed with exit code 1
My questions are:
My only guess for question 2 is that maybe the Future needs to be accessed via a Lock, and polling it from the main thread at the same moment as it is marked as completed/failed in the spawned thread is causing the crash. Or perhaps my knowledge of what works with regard to mixing async and threads in Nim is lacking.
For chronos, the general strategy is to rely on a cross-thread signal built for the purpose of notifying a future on a different thread to continue - see examples in https://status-im.github.io/nim-chronos/threads.html and https://github.com/status-im/nim-chronos/pull/543.
What we do is combine it with taskpools, so that cryptography jobs (signature verification in this particular example) run in a thread pool instead of a specific thread - this lets the whole thing scale with the amount of work: https://github.com/status-im/nimbus-eth2/blob/unstable/beacon_chain/gossip_processing/batch_validation.nim#L88
If you want to continue with std/asyncdispatch, the above might give you some ideas.