相关疑难解决方法(0)

C#async/await如何与更一般的结构相关,例如F#工作流或monad?

C#语言设计一直(历史上)一直致力于解决特定问题,而不是寻找解决潜在的一般问题:例如参见http://blogs.msdn.com/b/ericlippert/archive/2009/07/09/ "IEnumerable vs. coroutines"的iterator-blocks-part-one.aspx:

我们本来可以做得更普遍.我们的迭代器块可以看作是一种弱的协程.我们本可以选择实现完整的协同程序,并且只是使迭代器块成为协程的特例.当然,协同程序反过来不如一流的延续; 我们可以实现continuation,在continuation方面实现协程,并在协程方面实现迭代器.

或者http://blogs.msdn.com/b/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx for SelectMany作为(某种)Monads的代理人:

C#类型系统的功能不足以为monad创建通用抽象,这是创建扩展方法和"查询模式"的主要动力.

我不想问为什么会这样(已经给出了许多好的答案,特别是在Eric的博客中,这可能适用于所有这些设计决策:从性能到复杂性的增加,无论是编译器还是程序员).

我想要了解的是async/await关键字所涉及的"一般构造"(我最好的猜测是延续monad - 毕竟,F#async是使用工作流实现的,据我所知是一个延续monad),以及它们如何与它相关(它们如何不同?,缺少什么?,为什么存在差距,如果有的话?)

我正在寻找类似于我链接的Eric Lippert文章的答案,但与async/await相关而不是IEnumerable/yield.

编辑:除了很棒的答案,一些有用的链接到相关的问题和建议的博客文章,我正在编辑我的问题列出他们:

c# monads f# async-await

35
推荐指数
2
解决办法
2778
查看次数

调用堆栈没有说"你来自哪里",而是"你下一步去哪里"?

在上一个问题(获取对象调用层次结构)中,我得到了这个有趣的答案:

调用堆栈不是告诉你你来自哪里.它是告诉你下一步的去向.

据我所知,当到达函数调用时,程序通常会执行以下操作:

  1. 调用代码时:

    • 存储返回地址(在调用堆栈上)
    • 保存寄存器的状态(在调用堆栈上)
    • 写入将传递给函数的参数(在调用堆栈或寄存器中)
    • 跳转到目标函数

  2. 被叫目标代码中:

    • 检索存储的变量(如果需要)

  3. 返回过程:撤消我们调用函数时所做的操作,即展开/弹出调用堆栈:

    • 从调用堆栈中删除局部变量
    • 从调用堆栈中删除函数变量
    • 恢复寄存器状态(我们之前存储的状态)
    • 跳转到返回地址(我们之前存储的地址)

题:

如何将其视为"告诉您下一步的去向"而不是"告诉您从何而来"

在C#的JIT或C#的运行时环境中是否存在使得调用堆栈以不同方式工作的东西?

感谢有关调用堆栈描述的文档的任何指示 - 有大量关于传统调用堆栈如何工作的文档.

.net c# callstack

15
推荐指数
2
解决办法
2045
查看次数

C#await vs continuations:不太一样?

在阅读了Eric Lippert的回答之后,我得到了这样的印象,await并且call/cc几乎是同一枚硬币的两面,最多只有语法差异.然而,在尝试call/cc在C#5中实际实现时,我遇到了一个问题:要么我误解了call/cc(这是相当可能的),要么等待只是让人联想到call/cc.

考虑这样的伪代码:

function main:
    foo();
    print "Done"

function foo:
    var result = call/cc(bar);
    print "Result: " + result;

function bar(continuation):
    print "Before"
    continuation("stuff");
    print "After"
Run Code Online (Sandbox Code Playgroud)

如果我对call/cc的理解是正确的,那么应该打印:

Before
Result: stuff
Done
Run Code Online (Sandbox Code Playgroud)

至关重要的是,当调用延续时,程序状态将与调用历史一起恢复,以便foo返回main并永远不会返回bar.

但是,如果await在C#中使用,则调用continuation 不会还原此调用历史记录.foo返回bar,并且没有办法(我可以看到)await可以用来使正确的调用历史记录成为延续的一部分.

请解释一下:我是否完全误解了操作call/cc,或者await只是不完全相同call/cc


现在我知道了答案,我不得不说有充分的理由认为它们非常相似.考虑上面的程序在伪C#-5中的样子:

function main:
    foo();
    print "Done"

async function foo:
    var result = …
Run Code Online (Sandbox Code Playgroud)

c# continuation

13
推荐指数
1
解决办法
2528
查看次数

我们能否将Clojure的core.async描述为"延续传递风格"?

在Clojure的core.async库中,我们看到一个宏,它创建一个状态机,它围绕go块来创建处理阻塞IO的通道.

这似乎是 C#async Go-lang的goroutines 进行建模.

在The Seasoned Schemer中 - 他们描述了传递延续的技巧.(这似乎是基于电话/ cc).我们还看到了David Nolen的一个图书馆在Clojure 上的分隔延续.

在这里,他们将C#描述async为" 当前延续呼叫 ".

我的问题是我们可以将Clojure的core.async描述为" 延续传递风格 "吗?

或者是'延续'(分隔和无限制)一个超载的术语?


编辑:另外一点 - 大卫·诺伦已经说过核心.async:

在一个go块中,它给你一种错觉,你可以以同步的方式做这些事情,这样你就不必手动以连续传递方式编写代码.

continuations callcc clojure goroutine core.async

8
推荐指数
1
解决办法
786
查看次数

如何防止或恢复工作线程上的堆栈溢出?

我遇到过一种情况,根据minidump,某些文件在递归下降解析器中导致堆栈溢出.不幸的是我不能让我的手,这是否为了重现该问题(客户有保密性问题),这让我有点砍断诊断上真正的问题一时还文件的例子.

很明显,解析器需要一些关注,但现在我的首要任务是保持程序运行.作为权宜之计,我该怎样做才能阻止整个计划的落实?

我的第一选择是找到某种方法来预测我在堆栈上的空间不足以便我可以在溢出发生之前优雅地中止解析器.无法解析文件是可以接受的选项.第二种选择是让它发生,捕获错误并记录它,然后继续其余的数据.

解析发生在Parallel.ForEach()循环中.如果有帮助,我愿意将其换成其他方法.

编辑: 如果我能够获得当前线程堆栈的大小以及堆栈指针的位置,那么真正的杀手是什么.这可能吗?

编辑2: 我终于设法从某人那里取出一个样本文件并将错误记录在调试器中.事实证明,它根本不属于我们的代码 - HtmlAgilityPack中的某个地方发生了异常.所以看起来我将不得不尝试找到一个完全不同的方法.

.net c# stack-overflow multithreading

5
推荐指数
1
解决办法
322
查看次数

对迭代方法进行"迭代"

关于异步CTP的一些相关问题:

  • 我可以使用然后使用枚举器方法迭代Iterator Block(IEnumerable<T>返回yield T),以及.方法的模拟是什么?一个非调用方法如何接收和处理任何ed项然后呢?你能提供一个简短的例子吗?我只是没有看到它.GetEnumerator()MoveNext()Current()asyncasyncawaitContinueWith()

  • 此外,在下面的示例async方法中,MyAwaitable有一个GetAwaiter()方法.如果GetAwaiter()返回stringTHuh不是string,编译器不会抱怨.THuh和之间存在什么类型的约束/期望GetAwaiter()

    async Task<THuh> DoSomething()
    {
         var x = await new MyAwaitable("Foo");
    
         var y = await new MyAwaitable("Bar");
    
         return null;
    } 
    
    Run Code Online (Sandbox Code Playgroud)
  • 请解释C#规范草案的以下行.是否async Task<T>应该方法returndefault(T),将永远不会被使用?我看到一些似乎不符合此规则的示例 - 返回值似乎可以访问,值是非默认值.这个值无法访问吗?如果是这样,为什么尴尬难以接近的退货声明呢?

在具有Task<T>某些返回类型的异步函数中T,return语句必须具有可隐式转换为的表达式T,并且必须无法访问正文的端点.

  • 规范说"所有GetAwaiter,IsCompleted,OnCompleted和GetResult都是"非阻塞的" - 那么在什么方法中应该定义(可能)长时间运行的操作?

谢谢!

duck-typing pattern-matching c#-5.0 async-ctp

2
推荐指数
1
解决办法
579
查看次数

如何编写此方法以使其符合尾递归优化的条件?

有人知道一个算法来对尾部进行简单的递归吗?更具体地说,您将如何将算法应用于以下代码?

namespace Testing
{
    class Program
    {
        static void Main(string[] args)
        {
           Console.WriteLine(match("?**", "aaa"));
           Console.WriteLine(match("*#*?", "aa1$a1a1"));
           Console.WriteLine(match("*#*", "aa11"));
           Console.WriteLine(match("??*", "0110"));
           Console.WriteLine(match("", "abc"));
           Console.WriteLine(match("???", ""));
           Console.ReadLine();

        }


        public static bool match(string p, string s)
        {
            if (p.Length == 0)
                return true;
            if (p.Length > s.Length)
                return false;

            bool firstLetterMatches = false;
            char nextCharInStr = s[0];
            switch (p[0])
            {
                case '*':
                    firstLetterMatches = 'a'<= nextCharInStr && nextCharInStr <= 'z';
                    break;

                case '#':
                    firstLetterMatches = '0'<= nextCharInStr && nextCharInStr <= '9';
                    break;

                case …
Run Code Online (Sandbox Code Playgroud)

c# tail-recursion

1
推荐指数
1
解决办法
356
查看次数