davin

Just a little thinking and interest!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

.NET Framework Interfaces and Classes .

.net提供了很多 ViewModel能通过Xaml 数据绑定实现或集成属性到View 的Interface和Class。大部分这些实现都是通过 Observer pattern来实现的。(GoF写的23种设计模式中的一个)

Observer pattern

  在对象之间定义一个1对多的依赖,当一个对象的状态改变了,所有依赖它的对象将会得到通知并自动更新。

在.NET CLR 语言,像VB 或C#,Observer pattern在语言设计里使用Event形式来实现的。Event按照一个发布和订阅模型,凭借一个对象触发事件 并且其它订阅了事件的其它对象 将会接收到事件触发的通知。订阅者列表通过事件管理并且事 件可以注册或卸载 用+ -操作符。

Observer pattern 可以在发布者和订阅者之间松耦合。发布者完全不知道它的订阅者,当订阅者应用发布者.因此 我们可以说依赖是从订阅者到发布者.

没有这种模式,如果你想去通知一个对象的状态变化,你不得不持续地检查它的值由于状态引起的变化。这个过程叫做poll,并且它是观察者的对立面。为了poll变化,你需要持续的循环知道一个变化被发现并且对这一变化做出行动。这样非常低效,因此一个基于事件模型就很容易被亲睐。uml模型

YD6JE5V3M)9EG8A`218W}M2

INotifyPropertyChanged interface

InNoitfyPropertyChanged接口作为特殊的目的部分实现了Observe Pattern模式,通知订阅者,发布者的属性已经发生改变了。

Event PropertyChangedEventHandler

 

Onservable Collections:

INotifyCollectionChanged 和InNoitfyPropertyChanged 相似

ObservableCollection<T>

ReadOnlyObservableCollection<T>

CollectionViewSource:通过CollcetionViewSource可以Grouping Sorting Filtering

 

并发处理:

线程:在一个应用程序的进程里会有多个线程,当进程在运行,操作系统会决定哪个线程将会运行并且运行多久,每个线程在被终止之前和新线程开启之前可以处理任何代码。

在单cpu,单核的机器,没有真正意义上的并发,因为Cpu在一个时间总是只能执行一个指令,在非多处理器机器上并发是个假象。但是很多种情况线程极为有用,特别是当避免绑定任务阻塞的时候。

绑定任务是一个瓶颈(bottleneck)需要在代码中克服,如果有更多的资源。任务会被绑定到许多不同的资源上,但不包括:

CPU速度

输入/输出的资源:网络,Cpu缓存,

 

例子:

IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int portNumber = 1500;
TcpListener server = new TcpListener(ipAddress, portNumber);
try
{
server.Start();
// This call blocks until a client is received
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client connected!");
client.Close();
}
catch(SocketException ex)
{
Console.WriteLine("Socket Exception caught: {0}", ex);
}
finally
{
server.Stop();
}
Console.ReadKey();

AcceptTcpClient()是一个阻塞的调用,下一行代码不会执行直到AcceptTcpClient()返回结果。但是AcceptTcpClient()依赖于TCP客户端连接到端口,这个相应时间可能是很快,也可能是几个小时,但是在这个阻塞的时间里,应用程序除了等待不能做任何事情这时多线程就有作用了,调用AcceptTcpClient可以运行在不同的线程里,其它线程可以自由的继续处理其他有用的事情.一个线程阻塞了,主线程可以继续。不过框架提供异步调用阻塞方法的能力。TcpListener暴露了BeginAcceptTcpClient and EndAcceptTcpClient方法,因此上面的代码可以这样写:

TcpListener server = new TcpListener(ipAddress, portNumber);
try
{
server.Start();
// This call returns immediately, but there is no guarantee when a client
connects
server.BeginAcceptTcpClient(new AsyncCallback(ClientConnected), server);
}
catch(SocketException ex)
{
Console.WriteLine("Socket Exception caught: {0}", ex);
server.Stop();
}
Console.ReadKey();

 

private static void ClientConnected(IAsyncResult asyncResult)
{
TcpListener server = asyncResult.AsyncState as TcpListener;
TcpClient client = server.EndAcceptTcpClient(asyncResult);
Console.WriteLine("Client connected!");
server.Stop();
}

这只是其中的一种方式,服务器可以在不同线程上监听连接,以至于应用程序不会阻塞并且能够持续处理任务。

 

Increased Complexity

线程可能允许绑定任务保留功能和响应,但是这带来了高代价,不仅仅是应用程序更难理解,另外一个问题就是多线程应用程序极其难调式,开发者因为他们的程序执行没有可预见的顺序。线程意味着程序会在任意时间停住并且在返回原始的线程继续之前运行不同的线程。

 

共享内存

问题主要发生在内存共享在2个或多个线程之间。如果共享内存是只读,就没有太多问题因为夸线程读取的资源都能保持一致。然而,如果有一个线程会写到内存,其它线程读取的数据就会不一致。克服这点的办法就是保证共享内存的数据是不可变,但是他限制了线程额使用。如果共享内存可写,访问那些可读写的数据一定会mediated以至于数据在多个线程之间保持一致。

 

竞争Race Condition

example:

object lockObj = new object();
IList<string> list = new List<string>();
list.Add("Hello");

// multi-threaded code
lock(lockObj)
{
if(list.Count > 0)
{
list.RemoveAt(0);
}
}

很多代码在多线程里面就容易出现并发错误,如上面的代码在2个线程里面运行T1,T2,当T1检查list的Count属性并且返回value1.当操作系统停住T1,切换执行T2.T2检查Count属性并且得到Value1,T2继续执行if语句里面的内容,remove列表中的第一个string,如果这时候T1也刚好在执行remove操作,这样就会抛出ArgumentOutOfRangeException

为了阻止这种竞争,应该给代码加锁,这样才能保证访问是受限制的,一次只有一个线程。

object lockObj = new object();
IList<string> list = new List<string>();
list.Add("Hello");

// multi-threaded code
lock(lockObj)
{
if(list.Count > 0)
{
list.RemoveAt(0);
}
}

现在list是阻止并发访问。

 

Deadlock…

 

Thread in wpf and silverlight : 在wpf中有2个线程,一个用来rendering,另一个用来处理UI和应用程序代码,不过第二个线程有多个响应,如果我们用一个button click事件调用System.Threading.Thread.Sleep(10000),整个UI线程将会完全无响应10秒,这是因为负责更新用户界面的线程就是当前处理button event的线程,通常的,这不是问题。但是,如果你的Model和ViewModel 从线程接受一个事件不是一UI线程,其它想尝试更新UI都会以这个InvalidOperationException.失败。

dispatcher and dispatcherObjects

example:

ViewModel viewModel = DataContext as ViewModel;
Dispatcher.Invoke(
(Action)delegate
{
viewModel.Messages.Add(message);
}
);

posted on 2011-06-05 22:08  davin  阅读(1097)  评论(0编辑  收藏  举报