当前位置:  开发笔记 > 编程语言 > 正文

我只是没有得到延续!

如何解决《我只是没有得到延续!》经验,为你挑选了4个好方法。

他们是什么,他们有什么好处?

我没有CS学位,我的背景是VB6 - > ASP - > ASP.NET/C#.任何人都能以清晰简洁的方式解释它吗?



1> John Milliki..:

想象一下,如果程序中的每一行都是一个单独的函数.每个接受作为参数的下一行/要执行的函数.

使用此模型,您可以在任何行"暂停"执行并稍后继续执行.您还可以执行创造性操作,例如暂时跳过执行堆栈以检索值,或将当前执行状态保存到数据库以便稍后检索.


我也喜欢它,但哪一部分恰好是延续?

2> Dustin..:

你可能比你想象的更好地理解它们.

例外是"仅向上"延续的一个例子.它们允许堆栈内部的代码调用异常处理程序来指示问题.

Python示例:

try:
    broken_function()
except SomeException:
    # jump to here
    pass

def broken_function():
    raise SomeException() # go back up the stack
    # stuff that won't be evaluated

生成器是"向下"延续的例子.它们允许代码重新进入循环,例如,创建新值.

Python示例:

def sequence_generator(i=1):
    while True:
        yield i  # "return" this value, and come back here for the next
        i = i + 1

g = sequence_generator()
while True:
    print g.next()

在这两种情况下,这些都必须特别添加到语言中,而在具有延续的语言中,程序员可以创建这些不可用的东西.



3> Kyle Cronin..:

提醒一下,这个例子并不简洁,也不是特别清楚.这是对continuation的强大应用的演示.作为VB/ASP/C#程序员,您可能不熟悉系统堆栈或保存状态的概念,因此这个答案的目标是演示而不是解释.

Continuations非常通用,是一种保存执行状态并在以后恢复的方法.以下是使用Scheme中的continuation的协作多线程环境的一个小例子:

(假设操作在此处未定义的全局队列上按预期排队和出列工作)

(define (fork)
  (display "forking\n")
  (call-with-current-continuation
   (lambda (cc)
     (enqueue (lambda ()
                (cc #f)))
     (cc #t))))

(define (context-switch)
  (display "context switching\n")
  (call-with-current-continuation
   (lambda (cc)
     (enqueue
      (lambda ()
        (cc 'nothing)))
     ((dequeue)))))

(define (end-process)
  (display "ending process\n")
  (let ((proc (dequeue)))
    (if (eq? proc 'queue-empty)
        (display "all processes terminated\n")
        (proc))))

这提供了一个函数可以使用的三个动词 - fork,context-switch和end-process.fork操作分叉线程并在一个实例中返回#t而在另一个实例中返回#f.上下文切换操作在线程之间切换,而end-process终止线程.

以下是它们的使用示例:

(define (test-cs)
  (display "entering test\n")
  (cond
    ((fork) (cond
              ((fork) (display "process 1\n")
                      (context-switch)
                      (display "process 1 again\n"))
              (else (display "process 2\n")
                    (end-process)
                    (display "you shouldn't see this (2)"))))
    (else (cond ((fork) (display "process 3\n")
                        (display "process 3 again\n")
                        (context-switch))
                (else (display "process 4\n")))))
  (context-switch)
  (display "ending process\n")
  (end-process)
  (display "process ended (should only see this once)\n"))

输出应该是

entering test
forking
forking
process 1
context switching
forking
process 3
process 3 again
context switching
process 2
ending process
process 1 again
context switching
process 4
context switching
context switching
ending process
ending process
ending process
ending process
ending process
ending process
all processes terminated
process ended (should only see this once)

那些在课堂上学习分叉和穿线的人经常会给出类似的例子.这篇文章的目的是证明通过延续,你可以在一个线程中通过手动保存和恢复其状态 - 它的延续 - 来获得类似的结果.

PS - 我想我在On Lisp中记得类似的东西,所以如果你想看专业代码,你应该检查一下这本书.



4> Paul Johnson..:

考虑延续的一种方法是作为处理器堆栈.当你"使用current-continuation c调用"时,它调用你的函数"c",传递给"c"的参数是你当前的堆栈,上面包含你所有的自动变量(表示为另一个函数,称之为"k") ").与此同时,处理器开始创建一个新的堆栈.当你调用"k"时,它会在原始堆栈上执行"从子程序返回"(RTS)指令,跳回原来的"call-with-current-continuation"(从现在起"call-cc")的上下文on)并允许您的程序像以前一样继续.如果您将参数传递给"k",那么这将成为"call-cc"的返回值.

从原始堆栈的角度来看,"call-cc"看起来像是一个普通的函数调用.从"c"的角度来看,您的原始堆栈看起来像一个永不返回的函数.

有一个关于数学家的老笑话,他通过爬进笼子,锁定它,并宣称自己在笼子外面,而其他一切(包括狮子)在里面捕获了一只笼子里的狮子.延续有点像笼子,"c"有点像数学家.你的主程序认为"c"在里面,而"c"认为你的主程序在"k"里面.

您可以使用continuation创建任意控制流结构.例如,您可以创建一个线程库."yield"使用"call-cc"将当前的continuation放在队列中,然后跳转到队列头部的那个.信号量也有自己的暂停连续队列,并通过将其从信号量队列中取出并将其放入主队列来重新安排线程.

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有