Этот код действительно расширяет границы моего понимания, поэтому терпите меня.
Ранее я реализовал сопрограммы в Racket в следующем коде:
;; Coroutine definition
(define (make-generator procedure)
(define last-return values)
(define last-value #f)
(define status 'suspended)
(define (last-continuation _)
(let ([result (procedure yield)])
(last-return result)))
(define (yield value)
(call/cc (lambda (continuation)
(set! last-continuation continuation)
(set! last-value value)
(set! status 'suspended)
(last-return value))))
(lambda args
(call/cc (lambda (return)
(set! last-return return)
(cond ((null? args)
(let ()
(set! status 'dead)
(last-continuation last-value)))
((eq? (car args) 'coroutine?) 'coroutine)
((eq? (car args) 'status?) status)
((eq? (car args) 'dead?) (eq? status 'dead))
((eq? (car args) 'alive?) (not (eq? status 'dead)))
((eq? (car args) 'kill!) (set! status 'dead))
(#t (apply last-continuation args)))))))
;;Define a function that will return a suspended coroutine created from given args and body forms
(define-syntax (define-coroutine stx)
(syntax-case stx ()
((_ (name . args) . body )
#`(define (name . args)
(make-generator
(lambda (#,(datum->syntax stx 'yield))
. body))))))
Что я хочу сделать, так этореализовать обработчик исключений (with-handlers), который вызывает функцию (yield).Идея состоит в том, что второй поток может посылать сигнал потоку, оценивая сопрограмму, заставляя ее выдавать, когда он работает слишком долго.
Я пробовал следующее в лямбде args, который успешно вернулся рано, но позжеоценки сопрограммы (my-coroutine 'dead?) вернули, что сопрограмма находилась в' dead состоянии:
(with-handlers
([exn:break?
(lambda (break)
(yield 'coroutine-timeout))])
(break-enabled #t) ;register for yield requests from coroutine manager thread
(last-continuation last-value))))
В качестве альтернативы я попробовал следующее, но он не дал процедуры, котораяможет применяться к аргументам:
(with-handlers
([exn:break?
(lambda (break)
(set! last-continuation (exn:break-continuation break))
(set! last-value 'coroutine-timeout)
(set! status 'suspended)
(last-return 'coroutine-timeout))])
(break-enabled #t) ;register for yield requests from coroutine manager thread
(last-continuation last-value))))
Я пытаюсь понять, как продолжения и исключения взаимодействуют / блокируют друг друга.Кажется, мне может понадобиться как-то использовать параметры?
Как мне успешно написать обработчик сигнала, который будет (давать) правильно, чтобы я мог возобновить сопрограмму позже?
Редактировать: Ясмешивание метафор здесь (кооперативная и упреждающая многопоточность).Тем не менее, мой вопрос кажется мне возможным (с точки зрения непрофессионала), так как я могу оценить функции, определенные в моей сопрограмме (включая (yield)) из обработчика исключений.По сути, я пытаюсь ограничить нехватку ресурсов в моих рабочих потоках, а также уменьшить определенный класс тупиков (где задача 1 может быть завершена только после выполнения задачи 2, и нет свободных потоков для задачи 2 для выполнения).
Я написал (go) функцию для этих сопрограмм, которая смоделирована после go-подпрограмм go.Я предполагаю, что они достигают своего асинхронного поведения в отдельных потоках, имея совместные проверки доходности в основном коде, которым они управляют.Возможно, он работает в виртуальной машине, как вы предложили, и есть проверки, возможно, их операторы имеют проверки.Как бы то ни было, я пытаюсь добиться похожего поведения с другой стратегией.