NCindy

.net 2.0平台上的高性能网络程序开发框架
随笔 - 45, 文章 - 0, 评论 - 127, 引用 - 4
数据加载中……

置顶随笔

[置顶]CCR用户指南

posted @ 2007-12-09 20:28 iceboundrock 阅读(111) | 评论 (1)编辑

2008年3月19日

Windbg点滴

暂记下提纲,培训完回来慢慢写。
1. 设置

2. 下断点

3. 查看进程信息

4. 查看线程调用栈(Native&Managed)

5. 查看Managed内存

posted @ 2008-03-19 10:12 iceboundrock 阅读(35) | 评论 (0)编辑

2008年2月16日

MySQL Connector/Net 5.20安装后无法在VS2008中正常使用的问题

安装了MySQL Connector/Net 5.20之后在VS2008中新建连接,居然直接报告错误

Package Load Failure

Package 'MySQL Connector Net 5.2.0' has failed to load properly ( GUID = {79A115C9-B133-4891-9E7B-242509DAD272} ). Please contact package vendor for assistance. Application restart is recommended, due to possible environment corruption. Would you like to disable loading this package in the future? You may use 'devenv /resetskippkgs' to re-enable package loading.

反复安装几次都无效,只好求助万能的google了,看来这个问题还是普遍存在的,总结一下解决方法:

首先执行一条命令:msiexec /a MySql.Data.msi /qb TARGETDIR="C:\MySQL_VS",将安装包解压到C:\MySQL_VS目录中,然后复制C:\MySQL_VS\Visual Studio Integration目录到C:\Program Files\MySQL\MySQL Connector Net 5.2.0目录

然后修改注册表中的:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Packages\{79A115C9-B133-4891-9E7B-242509DAD272}

它里面的CodeBase字段中多写了一个“\”符号,删除多余的“\”之后,重启VS2008就可以了。

成名已久MySQL居然犯下这样的低级错误,真不知道是因为不重视.net还是因为他们的测试不够。

posted @ 2008-02-16 14:50 iceboundrock 阅读(155) | 评论 (0)编辑

2008年1月22日

LAMP周边点滴

SSH

这绝对是个好东东,配合putty简直是彪悍的一塌糊涂啊。

SSH首先是地球人都知道的远程登录功能,这就不说了。说几个个比较有特色的吧。

Tunnel功能

可以在Putty的Session设置界面,Connection->SSH->Tunnel中增加隧道,将一个本机的端口和一个远程的端点(Endpoint,IP:Port)关联起来。这个功能主要好处就是可以只在防火墙上开放一个22端口,防火墙后面的主机就都可以被暴露出来了,相对安全,配置起来也省力。

SSH的private key

这个可以用putty套件里面的PUTTYGEN.EXE来生成,上传公钥到到Ubuntu的~/目录中,然后用下面这串命令起用公钥

cd ~

mkdir .ssh

ssh-keygen -i -f public.pub >  .ssh/authorized_keys

再在putty中设置使用私钥进行认证,为了方便,还可以使用pagent来管理Session对应的私钥。

Putty的字体和字符集

个人感觉设置为Consolas比较好看,同时将Window->Translation中的字符集设置为UTF-8

Apache的启动、停止和重启控制

Ubuntu中使用命令:/usr/sbin/apache2ctl [start|stop|restart]

 

Xdebug

php的调试是一件比较头疼的事情,昨天还为一个很小的错误折腾到半夜2点,今天痛下决心非要找出一款合适的调试器不可。终于被我看到了Xdebug,加载这个模块之后,一个页面出现的所有未捕获异常都会用一个很简洁明了的表格显示出来,终于轻松了,还可以配合客户端进行代码级别调试。

posted @ 2008-01-22 17:53 iceboundrock 阅读(41) | 评论 (0)编辑

2007年12月23日

并行与并发编程学习心得

最近一直在学习并行与并发相关的东西,从用CCR户手册到erlang论文,从Channel 9的视频到MSDN的文章到,略有心得拿出来分享一下:

就像多任务操作系统中一个进程不能直接访问(OK,起码是不能很轻松的访问)另外一个进程的内存

思路

分离异步操作的执行方法和数据提供。一个有意义的程序执行需要两个部分:代码和数据。如果代码得到了数据之后就可以去执行了,能够并行执行的代码中,共享的数据越少越好,共享数据越少,需要锁定的地方就越少,效率提高,出错的可能降低。erlang中甚至要求两个不同的进程之间只能通过消息传递数据。

CCR使用Port来进行消息传递。port是将数据传递给代码的载体。当数据被投递到port中,port会根据元素类型将之和port上绑定的处理函数结合在一起组成一个Task,然后放入DispatcherQueue中等待执行。

 

 

并行与并发

并发与并行为啥重要有啥好处就不再多说了。谈谈并发与并行编程中常见的问题和困难吧。

  • 共享内存:传统的处理方式中,往往需要在多个并行的线程中共享数据,这是一个很容易出错的地方。锁的多了性能差,锁的少了更加可能会导致程序运行出现莫名其妙的问题。无论是CCR还是erlang,对这个问题的解决办法都很直接,避免使用共享内存,erlang更加严格,
  • 多个线程之间的同步:并发运行的多个线程之间往往是有关系的
  • 错误处理:如何找到错误的上下文,如何处理多个并发操作中部分成功部分失败的情况,都是

单元测试

 

 

单元测试之外的问题

posted @ 2007-12-23 00:08 iceboundrock 阅读(155) | 评论 (0)编辑

2007年12月18日

并发和协调运行时

原文链接

微软最近发布了为机器人编写应用的新的Microsoft Robotics Studio的预览版。这些新的工具很有趣,但是它应该比仅仅为机器人编程更加有趣。

 

Dispatcher类

当你的应用程序初始化的时候,你首先希望构造一个Dispatcher对象来管理一组线程。它实际上是一个线程池。和CLR的线程池一样,这些线程调用方法(通过delegate)来执行任务:

public sealed class Dispatcher : IDisposable {
    public Dispatcher();
    public Dispatcher(Int32 threadCount, String threadPoolName);
    public Dispatcher(Int32 threadCount, ThreadPriority priority,
        String threadPoolName);
    public ICollection<DispatcherQueue> DispatcherQueues { get; }
    ... // Other members not shown
}

当你构造Dispatcher对象时,可以把你想要的线程数传递给构造函数。在默认情况下,Dispatcher为每个CPU创建一个线程。注意,一个Dipatcher对象创建的线程数量是固定的,Dispatcher没有动态的创建或者销毁线程的逻辑。和CLR线程池不同,没有用来定期检查工作负载并动态调整线程池中线程数量的的特殊线程。这简化了Dispatcher线程池逻辑,并且使它更加高效。

当构造一个Dispatcher的时候,你还可以设定线程调度的优先级。默认情况下线程的优先级为普通。你还可以设置Dispatcher创建的线程的名称,当Dispatcher内部创建线程时,它会将线程对象的Name属性赋值为你设定的名字。这个名字可以帮助你进行调试,当你在Visual Studio中调试的时候还可以在线程窗口中看到它。

不像CLR中全局唯一的线程池,CCR允许你通过创建多个Dispatcher对象来创建多个线程池。这还使得你可以为不同类型的任务创建不同的线程池,如果你需要的话,还可以为每个线程池设定不同的优先级。

DispatcherQueue类

在你创建了一个Dispatcher之后,你将希望创建一个DispatcherQueue对象。一个DispatcherQueue维护了一个准备执行的delegate的队列。Dispatcher的线程等待有元素出现在DispatcherQueue中。通常DispatcherQueue是空的,并且Dispatcher的线程处于等待状态。当有元素出现时,Dispatcher线程苏醒,并且行该元素对应的方法。

public sealed class DispatcherQueue : IDisposable {
    // Use CLR thread pool; not Dispatcher
    public DispatcherQueue(string name); 
    public DispatcherQueue(String name, Dispatcher dispatcher);

    public virtual void Enqueue(ITask task);
    public virtual void EnqueueTimer(
        TimeSpan timeSpan, Port<DateTime> timerPort);
   
    public void Dispose();

    ... // Other members not shown
}

对于CLR的线程池,如果有1000个元素在排队,当这1000个元素被处理完之前你没有办法让一个新的元素被处理。但是在CCR中,你可以分配一个DispatcherQueue给大多数的工作项,同时分配另外一个DispatcherQueue对象给高优先级的工作项。Dispatcher对象轮循所有与之关联的DispatcherQueue,并从中取出元素。我还需要指出,如果在DispatcherQueue的构造函数中不带Dispatcher参数将可能会创建一个使用CLR线程池而不是Dispatcher的DispatcherQueue对象。

通常情况下,应用程序在初始化的时候构造Dispatcher和DispatcherQueue对象,并在程序余下的生命周期中使用它们。所以,现在我们把注意力转到那些应用程序常常构造、使用一小段时间然后就废弃的对象上。

Port和Arbiter类

一个泛型的Port<T>对象代表一个队列,队列中所有的元素类型都是T。你可以认为port是一种回调函数的参数队列,类似于ThreadPool.QueueUserWorkItem方法的state参数。

当异步操作完成,它的结果会投递到一个Port对象中。

posted @ 2007-12-18 14:47 iceboundrock 阅读(51) | 评论 (0)编辑

其它并发方法

原文链接

CCR可以表达(当需要的时候通过简单的助手方法)各种其它的并发方法,例如:

  1. .net中的异步编程模型(APM):MSDN杂志中的Concurrent Affairs文章有一些用CCR适配器助手和APM APIs来调用系统类库的例子。
  2. Futures:Futures被表达为立即从一个类中返回一个port,并且并行的激活处理函数。使用一个dispatcher queue来并行的执行调用者和被调用的代码,然后一个操作系统事件会阻塞一个等待结果的公共方法(假定一个同步未来模式(assuming a synchronous future pattern),看不懂,再汗一个-_-!!!)。为了调度未来工作项(future work items),CCR调度器设计自然的在适当的时候充分利用CPU处理能力来执行高效计划,使用用户定义的策略来进行速度控制和负载均衡。分发队列是FIFO对,但是DispatcherQueue的实现暴露了一组虚方法,允许继承类来实现LIFO,随机插入等等。
  3. 连接(joins):连接编程在操作系统中出现已经有很长时间了(WaitForMultiple, I/O Completion ports in NT, etc),CCR更加用动态连接和多元素接收器对连接进行了扩展。
  4. 传统的线程原语,例如读写锁、锁和监控器(monitors):CCR可以通过port和仲裁器来表达线程同步原语,并且取代显式的对共享内存的锁定。问题就从保护共享内存变成了调度和协议设计。

posted @ 2007-12-18 10:36 iceboundrock 阅读(58) | 评论 (0)编辑

2007年12月17日

与非CCR代码互操作

     摘要: CCR可以轻松的承载STA组件或者与它互操作  阅读全文

posted @ 2007-12-17 22:39 iceboundrock 阅读(67) | 评论 (0)编辑

失败处理

原文链接

传统的失败处理策略遵循如下模式:

  1. 对于同步方法调用,调用者检查一个或者多个返回值。被调用的方法使用调用者的执行上下文(通常执行上下文是一个线程)来运行。
  2. 使用结构化异常处理,调用者将同步方法调用包裹在try/catch/finally语句中,依赖catch{}块的执行来处理错误或者使用catch{}块加上显式的检查被调用方法的返回值。
  3. 依赖于被调用组件的各种补偿实现的事务,操作系统基础设置和通常很昂贵的机制来跟踪跨越多个线程的上下文。

上述所有方法都不能很容易的用于并发、异步执行,特别是前两种方法根本就不可能用于异步编程。方法在任意的上下文中执行,可能和调用者并行执行。除非有阻塞操作来收集异步操作的结果,阻塞一个在调用者上下文中的线程,失败或者成功都不能很容易的被检测。CLR中的异步编程模型使用Begin/End调用,引入了附加的复杂性,因为附加调用和无论操作结果如何都会被调用到的回调中的异常处理中都需要做失败处理。启动异步操作的代码不是进行失败处理的地方使得代码难以阅读。

CCR分两步解决失败处理的问题:

  1. 使用Choice和MultipleItemGather仲裁器处理显式或者本地异常。与迭代器合在一起,它们提供了一个类型安全并强壮的方法来处理失败,因为他们强制程序员将成功的情况和失败的情况分别写在两个不同的方法中并且有一个普通的继续(and then also have a common continuation)。例8、13和20分别展示了使用Choice, MultipleItemGather 和在一个迭代器中的Choice来进行显式错误处理(explicit error handling)。
  2. 隐式或者分布式一场处理被称作Causalities,它允许跨越多个异步操作嵌套和扩展。它与事务共享逻辑上下文概念或者将操作分组并为异步并发环境扩展它。这种机制可以跨越机器边界延伸。

因果关系(Causalities)

Causality是指可以跨多个执行上下文的一串操作,分支或者连接,创建一颗只有一个根的执行逻辑树。这个逻辑分组称为因果关系上下文,隐式的从一个消息的发送者传递到接收者。

Causalities是一种结构化异常机制在多线程环境的扩展。它们允许嵌套,但是依然处理多个并发的一场和与其他的causalities合并(例如因为连接(joins)操作)。

例22.

         void SimpleCausalityExample()
        {
1:          Port<Exception> exceptionPort = new Port<Exception>();
            // create a causality using the port instance
2:          Causality exampleCausality = new Causality("root cause", exceptionPort);
            // add causality to current thread
3:          Dispatcher.AddCausality(exampleCausality);

            // any unhandled exception from this point on, in this method or
            // any delegate that executes due to messages from this method,
            // will be posted on exceptionPort.
            
            Port<int> portInt = new Port<int>();
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false,portInt,IntHandler)
            );
            
            // causalities flow when items are posted or Tasks are scheduled
4:          portInt.Post(0);

            // activate a handler on the exceptionPort
            // This is the failure handler for the causality
5:          Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, exceptionPort,
                delegate (Exception ex)
                {
                    // deal with failure here
                    Console.WriteLine(ex);
                })
            );
        }

        void IntHandler(int i)
        {
            // print active causalities
            foreach (Causality c in Dispatcher.ActiveCausalities)
            {
                Console.WriteLine(c.Name);
            }
            // expect DivideByZeroException that CCR will redirect to the causality
6:          int k = 10 / i;
        }

在上面的例子中我们演示了一个简单的场景,causalities帮助处理跨多个异步操作的错误。代码的关键步骤如下:

  1. 创建一个Port<Exception>实例exceptionPort来存储任何从causality上下文中抛出的异常。
  2. 使用上面创建的异常exceptionPort和一个友好的名称做为构造函数的参数来创建一个新的Causality实例。
  3. 将这个causality加入到Dispatcher的causalities列表中。
  4. 一个元素被投递到port,因为这个投递动作发生在causality的上下文中,他将会隐式的“附加”它的causality到被投递的元素。当一个处理器处理这个元素时,附加在元素上的causality将会被添加到执行接收器的线程中。任何接收器中抛出的异常将会被投递到causality中的exceptionPort。
  5. 一个接收器在exceptionPort上被激活,所以在所有异步操作中,所有的抛出但是没有被处理的异常都会被接收到。
  6. 因为有元素被投递到portInt实例上,所以处理器被调度,抛出一个DivideByZeroException。CCR调度器自动将这个异常重定向到关联在causality上的exceptionPort。

 

例23.

         public void NestedCausalityExample()
        {
            Port<Exception> exceptionPort = new Port<Exception>();
            Causality parentCausality = new Causality(
                "Parent", 
                exceptionPort);
            Dispatcher.AddCausality(parentCausality);

            Port<int> portInt = new Port<int>();
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, portInt, IntHandlerNestingLevelZero)
            );
            portInt.Post(0);

            // activate a handler on the exceptionPort
            // This is the failure handler for the causality
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, 
                exceptionPort,
                delegate (Exception ex)
                {
                    // deal with failure here
                    Console.WriteLine("Parent:" + ex);
                })
            );
        }

        void IntHandlerNestingLevelZero(int i)
        {
            // print active causalities
            foreach (Causality c in Dispatcher.ActiveCausalities)
            {
                Console.WriteLine("Before child is added:   " + c.Name);
            }

            // create new child causality that will nest under existing causality
            Port<Exception> exceptionPort = new Port<Exception>();
            Causality childCausality = new Causality(
                "Child", 
                exceptionPort);
            Dispatcher.AddCausality(childCausality);

            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, 
                exceptionPort,
                delegate (Exception ex)
                {
                    // deal with failure here
                    Console.WriteLine("Child:" + ex);
                })
            );

            // print active causalities
            foreach (Causality c in Dispatcher.ActiveCausalities)
            {
                Console.WriteLine("After child is added:    " + c.Name);
            }

            // attach a receiver and post to a port
            Port<int> portInt = new Port<int>();
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, portInt, IntHandlerNestingLevelOne)
            );
            portInt.Post(0);
        }

        void IntHandlerNestingLevelOne(int i)
        {
            throw new InvalidOperationException(
                  "Testing causality support. Child causality will catch this one");
        }

例子的输出:

Before child is added:   Parent
After child is added:    Child
Child:System.InvalidOperationException: Testing causality support. Child causality will catch this one
   at Examples.Examples.IntHandlerNestingLevelOne(Int32 i)
 in C:\mri\main\CCR\testsrc\UnitTests\ccruserguideexamples.cs:line 571
   at Microsoft.Ccr.Core.Task`1.Execute()
 in C:\mri\main\CCR\src\Core\Templates\GeneratedFiles\Task\Task01.cs:line 301
   at Microsoft.Ccr.Core.TaskExecutionWorker.ExecuteTaskHelper(ITask currentTask)
 in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1476
   at Microsoft.Ccr.Core.TaskExecutionWorker.ExecuteTask(ITask& currentTask, DispatcherQueue p)
 in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1376
   at Microsoft.Ccr.Core.TaskExecutionWorker.ExecutionLoop()
 in C:\mri\main\CCR\src\Core\scheduler_roundrobin.cs:line 1307
 

在上面的例子中,我们演示了一个嵌套的异步序列:

  1. NestedCausalityExample方法向一个带接收器的port中加入了一个causality
  2. IntHandlerNestingLevelZero方法与NestedCausalityExample方法并行异步执行,向

 

 

连接和因果关系(Joins and Causalities)

 

 
 

例24.

         public void JoinedCausalityExample()
        {
            Port<int> intPort = new Port<int>();
            Port<int> leftPort = new Port<int>();
            Port<string> rightPort = new Port<string>();

            Port<Exception> leftExceptionPort = new Port<Exception>();
            Port<Exception> rightExceptionPort = new Port<Exception>();

            // post twice so two handlers run
            intPort.Post(0);
            intPort.Post(1);

            // activate two handlers that will execute concurrently and create
            // two different parallel causalities
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, intPort, 
                delegate (int i)
                {

                    Causality leftCausality = new Causality("left", leftExceptionPort);
                    Dispatcher.AddCausality(leftCausality);
                    // post item on leftPort under the context of the left causality
                    leftPort.Post(i);                    
                })
            );

            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, intPort, 
                delegate (int i)
                {
                    Causality rightCausality = new Causality("right", rightExceptionPort);
                    Dispatcher.AddCausality(rightCausality);
                    // post item on rightPort under the context of the right causality
                    rightPort.Post(i.ToString());                    
                })
            );

            // activate one join receiver that executes when items are available on
            // both leftPort and rightPort

            Arbiter.Activate(_taskQueue,
                Arbiter.JoinedReceive<int, string>(false, leftPort, rightPort,
                delegate (int i, string s)
                {
                    throw new InvalidOperationException("This exception will propagate to two peer causalities");
                })
            );

            // activate a handler on the exceptionPort
            // This is the failure handler for the causality
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, leftExceptionPort,
                delegate(Exception ex)
                {
                    // deal with failure here
                    Console.WriteLine("Left causality:  " + ex);
                })
            );

            // activate a handler on the exceptionPort
            // This is the failure handler for the causality
            Arbiter.Activate(_taskQueue,
                Arbiter.Receive(false, rightExceptionPort,
                delegate(Exception ex)
                {
                    // deal with failure here
                    Console.WriteLine("Right causality:  " + ex);
                })
            );
        }

例子的输出:

 Left causality:  System.InvalidOperationException: This exception will propagate to two peer causalities
Right causality:  System.InvalidOperationException: This exception will propagate to two peer causalities
 

为了可读性,上面的例子中大量使用了匿名方法来保持所有的逻辑都在一个方法中。这个例子演示了:

  • 两个独立的处理器创建了两个causalities(分别叫做:"left"和"right")
  • 向每个port中投递一个消息
  • 由于在两个port(leftPort和rightPort)上的连接条件被满足,所以第三个处理器被执行
  • 连接处理器在两个causalities的上下文中抛出一个异常

 

关键点是:当连接处理器(join handler)执行并且抛出异常,两个peer causalities被激活并且都独立的得到了投递到他们所负责的exception port上的异常。

重要:由于causalities使用常规的CCR ports来接收异常,你可以使用CCR协调原语来组合跨多个causalitites的异常处理。Joins,interleave和choice全都是合适的而且强大的方式来组合跨多个并发,多层异步操作的异常处理。

posted @ 2007-12-17 11:23 iceboundrock 阅读(65) | 评论 (0)编辑

2007年12月14日

迭代器

     摘要: CCR以新颖的方式使用了C# 2.0语言的迭代器功能:程序员可以用顺序的方式来编写代码,迭代返回(yielding)CCR仲裁器或者其他的CCR Task,而不需要使用delegates来嵌套异步行为(也叫做回调)。  阅读全文

posted @ 2007-12-14 14:30 iceboundrock 阅读(71) | 评论 (0)编辑

2007年12月12日

任务调度

     摘要: CCR第三个重要的组成部分是任务调度:当有接收器的port上有消息到达时如何生成任务和在有多个执行资源的机器上进行负载均衡。  阅读全文

posted @ 2007-12-12 18:03 iceboundrock 阅读(90) | 评论 (2)编辑