在这里,我们将给大家分享关于ReactOS源码分析(一)by:ProgrammeBoy的知识,让您更了解react源码深度解析慕课网的本质,同时也会涉及到如何更有效地.Net中的反应式编程(React
在这里,我们将给大家分享关于ReactOS 源码分析 (一) by:ProgrammeBoy的知识,让您更了解react源码深度解析 慕课网的本质,同时也会涉及到如何更有效地.Net中的反应式编程(Reactive Programming)、8 Traits of an Experienced Programmer that every beginner programmer should know、Cg Programming/ProgrammableGraphics Pipeline、com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码的内容。
本文目录一览:- ReactOS 源码分析 (一) by:ProgrammeBoy(react源码深度解析 慕课网)
- .Net中的反应式编程(Reactive Programming)
- 8 Traits of an Experienced Programmer that every beginner programmer should know
- Cg Programming/ProgrammableGraphics Pipeline
- com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码
ReactOS 源码分析 (一) by:ProgrammeBoy(react源码深度解析 慕课网)
ReactOS 源码分析
前言
ReactOS是一个开源的免费的操作系统,它致力于兼容现在最流行的操作系统windows,打破微软垄断的局面,这里我们为那些默默无闻的开发者致敬,他们开发reactos没有工资,没有补贴,没有…只有默默的写代码…这是一种精神..
代码分析
那我们就在最初引导阶段开始分析.首先我们假设我们的机器是i386机型. 引导磁盘是fat32格式.我的Reactos代码在D:/ReactOS/ReactOS_src/下,代码版本0.39
1. 系统开始启动
首先机器加电自检,然后检查启动盘,是从光盘还是硬盘启动呢?可能大家都知道,这是在BIOS里面设置的,这里我们是研究已经安装好的系统启动过程,就磁盘启动啦,首先找到启动磁盘,BIOS会检查磁盘的0面0磁道,1扇区,如果发现其为55aa结尾而且小于512字节就认为他就是一个合法的引导扇扇区(BootSector),然后把这个引导代码加载到0000:7c000处,然后跳转到这个地方执行,现在就把所有的控制权交给引导代码了,BIOS里的启动代码是固定在ROM里的,所以系统启动的代码就是那段引导程序代码,前面我们也假设了我们是fat32格式的磁盘.所以我们就从fat32.asm开始吧.
2 f at32.asm
代码位置: D:/ReactOS/ReactOS_src/boot/freeldr/bootsect/fat32.asm
代码如下:
org 7c00h
segment .text
bits 16 ;16位程序
start:
jmp short main
nop
数据结构如下
OEMName db 'FrLdr1.0'
BytesPerSector dw 512
SectsPerCluster db 0
ReservedSectors dw 32
main:
;初始化
xor ax,ax ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ;Make SS correct
mov bp,7c00h
mov sp,7c00h ; Setup a stack
cmp BYTE [BYTE bp+BootDrive],BYTE 0xff ; If they have specified a boot drive then use it
jne CheckSectorsPerFat
mov [BYTE bp+BootDrive],dl ; Save the boot drive
CheckSectorsPerFat:
cmp WORD [BYTE bp+SectorsPerFat],byte 0x00 ; Check the old 16-bit value of SectorsPerFat
jnz CheckFailed ; If it is non-zero then exit with an error
CheckTotalSectors: ; Check the old 16-bit value of TotalSectors & MaxRootEntries
cmp DWORD [BYTE bp+MaxRootEntries],byte 0x00; by comparing the DWORD at offset MaxRootEntries to zero
jnz CheckFailed ; If it is non-zero then exit with an error
CheckFileSystemVersion:
cmp WORD [BYTE bp+Fsversion],byte 0x00 ; Check the file system version word
jna GetDriveParameters ; It is zero,so continue
CheckFailed:
jmp PrintFileSystemError ; If it is not zero then exit with an error
GetDriveParameters:
CalcDriveSize:
LoadExtraBootCode:
;==========================================================
ReadSectors:
;========================================================
StartSearch:
; Now we must get the first cluster of the root directory
mov eax,DWORD [BYTE bp+RootDirstartCluster]
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jb ContinueSearch ; If not continue,if so then we didn't find freeldr.sys
jmp PrintFileNotFound
ContinueSearch:
mov bx,2000h
mov es,bx ; Read cluster to [2000:0000h]
call ReadCluster ; Read the cluster
; Now we have to find our way through the root directory to
; The osloADER.SYS file
xor bx,bx
mov bl,[BYTE bp+SectsPerCluster]
shl bx,4 ; BX = BX * 512 / 32
mov ax,2000h ; We loaded at 2000:0000
mov es,ax
xor di,di
mov si,filename
mov cx,11
rep cmpsb ; Compare filenames
jz FoundFile ; If same we found it
dec bx
jnz FindFile
jmp PrintFileNotFound
FindFile:
mov ax,es ; We didn't find it in the prevIoUs dir entry
add ax,2 ; So lets move to the next one
mov es,ax ; And search again
xor di,filename
mov cx,11
rep cmpsb ; Compare filenames
jz FoundFile ; If same we found it
dec bx ; Keep searching till we run out of dir entries
jnz FindFile ; Last entry?
; Get the next root dir cluster and try again until we run out of clusters
mov eax,DWORD [BYTE bp+RootDirstartCluster]
call GetFatEntry
mov [BYTE bp+RootDirstartCluster],eax
jmp StartSearch
FoundFile:
; display "Loading FreeLoader..." message
mov si,msgLoading ; Loading message
call PutChars ; display it
xor di,di ; ES:DI has dir entry
xor dx,dx
mov ax,WORD [es:di+14h] ; Get start cluster high word
shl eax,16
mov ax,WORD [es:di+1ah] ; Get start cluster low word
CheckStartCluster:
cmp eax,2 ; Check and see if the start cluster starts at cluster 2 or above
jnb CheckEndCluster ; If so then continue
jmp PrintFileSystemError ; If not exit with error
CheckEndCluster:
cmp eax,0ffffff8h ; Check and see if the start cluster is and end of cluster chain indicator
jb InitializeLoadSegment ; If not then continue
jmp PrintFileSystemError ; If so exit with error
InitializeLoadSegment:
mov bx,800h
mov es,bx
LoadFile:
cmp eax,0ffffff8h ; Check to see if this is the last cluster in the chain
jae LoadFileDone ; If so continue,if not then read the next one
push eax
xor bx,bx ; Load ROSLDR starting at 0000:8000h
push es
call ReadCluster
pop es
xor bx,5 ; BX = BX * 512 / 16
mov ax,es ; Increment the load address by
add ax,bx ; The size of a cluster
mov es,ax
pop eax
push es
call GetFatEntry ; Get the next entry
pop es
jmp LoadFile ; Load the next cluster (if any)
LoadFileDone:
mov dl,[BYTE bp+BootDrive] ; Load boot drive into DL
mov dh,[BootPartition] ; Load boot partition into DH
GetFatEntry:
shl eax,2 ; EAX = EAX * 4 (since fat32 entries are 4 bytes)
mov ecx,eax ; Save this for later in ECX
xor edx,edx
movzx ebx,WORD [BYTE bp+BytesPerSector]
push ebx
div ebx ; FAT Sector Number = EAX / BytesPerSector
movzx ebx,WORD [BYTE bp+ReservedSectors]
add eax,ebx ; FAT Sector Number += ReservedSectors
mov ebx,DWORD [BYTE bp+HiddenSectors]
add eax,ebx ; FAT Sector Number += HiddenSectors
pop ebx
dec ebx
and ecx,ebx ; FAT Offset Within Sector = ECX % BytesPerSector
; EAX holds logical FAT sector number
; ECX holds FAT entry offset
; Now we have to check the extended flags
; to see which FAT is the active one
; and use it,or if they are mirrored then
; no worries
movzx ebx,WORD [BYTE bp+ExtendedFlags] ; Get extended flags and put into ebx
and bx,0x0f ; Mask off upper 8 bits,Now we have active fat in bl
jz LoadFatSector ; If fat is mirrored then skip fat calcs
cmp bl,[BYTE bp+NumberOfFats] ; Compare bl to number of fats
jb GetActiveFatOffset
jmp PrintFileSystemError ; If bl is bigger than numfats exit with error
GetActiveFatOffset:
push eax ; Save logical FAT sector number
mov eax,[BYTE bp+SectorsPerFatBig] ; Get the number of sectors occupied by one fat in eax
mul ebx ; Multiplied by the active FAT index we have in ebx
pop edx ; Get logical FAT sector number
add eax,edx ; Add the current FAT sector offset
LoadFatSector:
push ecx
; EAX holds logical FAT sector number
; Check if we have already loaded it
cmp eax,DWORD [FatSectorInCache]
je LoadFatSectorAlreadyLoaded
mov DWORD [FatSectorInCache],eax
mov bx,7000h
mov es,bx
xor bx,bx ; We will load it to [7000:0000h]
mov cx,1
call ReadSectors
LoadFatSectorAlreadyLoaded:
mov bx,bx
pop ecx
mov eax,DWORD [es:ecx] ; Get FAT entry
and eax,0fffffffh ; Mask off reserved bits
ret
FatSectorInCache: ; This variable tells us which sector we currently have in memory
dd 0ffffffffh ; There is no need to re-read the same sector if we don't have to
; Reads cluster number in EAX into [ES:0000]
ReadCluster:
; StartSector = ((Cluster - 2) * SectorsPerCluster) + ReservedSectors + HiddenSectors;
PrintFileNotFound:
mov si,msgFreeLdr ; FreeLdr not found message
call PutChars ; display it
mov si,msgAnyKey ; Press any key message
call PutChars ; display it
jmp Reboot
msgFreeLdr db 'freeldr.sys not found',0dh,0ah,0
filename db 'FREELDR SYS'
msgLoading db 'Loading FreeLoader...',0
times 1022-($-$$) db 0 ; Pad to 1022 bytes
dw 0aa55h ; BootSector signature
好,看完代码也有单晕晕乎乎了,我们来总结下fat32.asm。首先加载到0000:7c00处,接下来就是那个结构体,而上面跳转到main函数那了.开始当然是对一些寄存器的初始化,接着就是检查BootSector的参数是否正确,接着计算整个磁盘的存储量,为什么要计算这个呢?为了检查磁盘是否支持LBA模式。再下面的工作就是查找freeldr.sys.并将其加载到内存0000:8000处,
其中又有fat文件格式的操作….
需要的知识点
对了freeldr目录下有个note.txt里面有内存分配表如下,大家好好看看:
Memory layout:
0000:0000 - 0000:0FFF: Interrupt vector table & BIOS data
0000:1000 - 0000:6FFF: Real mode stack area
0000:7000 - 0000:7FFF: Cmdline (multiboot)
0000:8000 - xxxx:xxxx: FreeLoader program & data area
xxxx:xxxx - 7000:7FFF: Random memory allocation heap
7000:8000 - 7000:FFFF: Protected mode stack area
8000:0000 - 8000:FFFF: File system read buffer
9000:0000 - 9000:FFFF: disk read buffer for BIOS Int 13h
A000:0000 - FFFF:FFFF: reserved
.Net中的反应式编程(Reactive Programming)
系列主题:基于消息的软件架构模型演变
一、反应式编程(Reactive Programming)
1、什么是反应式编程:反应式编程(Reactive programming)简称Rx,他是一个使用LINQ风格编写基于观察者模式的异步编程模型。简单点说Rx = Observables + LINQ + Schedulers。
2、为什么会产生这种风格的编程模型?我在本系列文章开始的时候说过一个使用事件的例子:
var watch = new FileSystemWatcher(); watch.Created += (s,e) => { var fileType = Path.GetExtension(e.FullPath); if (fileType.ToLower() == "jpg") { //do some thing } };
这个代码定义了一个FileSystemWatcher,然后在Watcher事件上注册了一个匿名函数。事件的使用是一种命令式代码风格,有没有办法写出声明性更强的代码风格?我们知道使用高阶函数可以让代码更具声明性,整个LINQ扩展就是一个高阶函数库,常见的LINQ风格代码如下:
var list = Enumerable.Range(1,10) .Where(x => x > 8) .Select(x => x.ToString()) .First();
能否使用这样的风格来编写事件呢?
3、事件流
LINQ是对IEnumerable<T>的一系列扩展方法,我们可以简单的将IEnumerable<T>认为是一个集合。当我们将事件放在一个时间范围内,事件也变成了集合。我们可以将这个事件集合理解为事件流。
事件流的出现给了我们一个能够对事件进行LINQ操作的灵感。
二、反应式编程中的两个重要类型
事件模型从本质上来说是观察者模式,所以IObservable<T>和IObserver<T>也是该模型的重头戏。让我们来看看这两个接口的定义:
public interface IObservable<out T> { //Notifies the provider that an observer is to receive notifications. Idisposable Subscribe(IObserver<T> observer); }
public interface IObserver<in T> { //Notifies the observer that the provider has finished sending push-based notifications. void OnCompleted(); //Notifies the observer that the provider has experienced an error condition. void OnError(Exception error); //Provides the observer with new data. void OnNext(T value); }
这两个名称准确的反应出了它两的职责:IObservable<T>-可观察的事物,IObserver<T>-观察者。
IObservable<T>只有一个方法Subscribe(IObserver<T> observer),此方法用来对事件流注册一个观察者。
IObserver<T>有三个回调方法。当事件流中有新的事件产生的时候会回调OnNext(T value),观察者会得到事件中的数据。OnCompleted()和OnError(Exception error)则分别用来通知观察者事件流已结束,事件流发生错误。
显然事件流是可观察的事物,我们用Rx改写上面的例子:
Observable.FromEventPattern<FileSystemEventArgs>(watch,"Created") .Where(e => Path.GetExtension(e.EventArgs.FullPath).ToLower() == "jpg") .Subscribe(e => { //do some thing });
注:在.net下使用Rx编程需要安装以下Nuget组件:
Install-Package Rx-main
三、UI编程中使用Rx
Rx模型不但使得代码更加具有声明性,Rx还可以用在UI编程中。
1、UI编程中的第一段Rx代码
为了简单的展示如何在UI编程中使用Rx,我们以Winform中的Button为例,看看事件模型和Rx有何不同。
private void BindFirstGroupButtons() { btnFirstEventMode.Click += btnFirstEventMode_Click; } void btnFirstEventMode_Click(object sender,EventArgs e) { MessageBox.Show("hello world"); }
添加了一个Button,点击Button的时候弹出一个对话框。使用Rx做同样的实现:
//得到了Button的Click事件流。 var clickedStream = Observable.FromEventPattern<EventArgs>(btnFirstReactiveMode,"Click"); //在事件流上注册了一个观察者。 clickedStream.Subscribe(e => MessageBox.Show("Hello world"));
有朋友指出字符串“Click”非常让人不爽,这确实是个问题。由于Click是一个event类型,无法用表达式树获取其名称,最终我想到使用扩展方法来实现:
public static IObservable<EventPattern<EventArgs>> FromClickEventPattern(this Button button) { return Observable.FromEventPattern<EventArgs>(button,"Click"); } public static IObservable<EventPattern<EventArgs>> FromDoubleClickEventPattern(this Button button) { return Observable.FromEventPattern<EventArgs>(button,"DoubleClick"); }
我们平时常用的事件类型也就那么几个,可以暂时通过这种方案来实现,该方案算不上完美,但是比起直接使用字符串又能优雅不少。
btnFirstReactiveMode.FromClickEventPattern() .Subscribe(e => MessageBox.Show("hello world"));
2、UI编程中存在一个很常见的场景:当一个事件的注册者阻塞了线程时,整个界面都处于假死状态。.net中的异步模型也从APM,EAP,TPL不断演化直至async/await模型的出现才使得异步编程更加简单易用。我们来看看界面假死的代码:
void btnSecondEventMode_Click(object sender,EventArgs e) { btnSecondEventMode.BackColor = Color.Coral; Thread.Sleep(2000); lblMessage.Text = "event mode"; }
Thread.Sleep(2000);模拟了一个长时间的操作,当你点下Button时整个界面处于假死状态并且此时的程序无法响应其他的界面事件。传统的解决方案是使用多线程来解决假死:
BtnSecondEventAsyncModel.BackColor = Color.Coral; Task.Run(() => { Thread.Sleep(2000); Action showMessage = () => lblMessage.Text = "async event mode"; lblMessage.Invoke(showMessage); });
这个代码的复杂点在于:普通的多线程无法对UI进行操作,在Winform中需要用Control.BeginInvoke(Action action)经过包装后,多线程中的UI操作才能正确执行,WPF则要使用dispatcher.BeginInvoke(Action action)包装。
Rx方案:
btnSecondReactiveMode.FromClickEventPattern() .Subscribe(e => { Observable.Start(() => { btnSecondReactiveMode.BackColor = Color.Coral; Thread.Sleep(2000); return "reactive mode"; }) .SubscribeOn(ThreadPoolScheduler.Instance) .ObserveOn(this) .Subscribe(x => { lblMessage.Text = x; }); });
一句SubscribeOn(ThreadPoolScheduler.Instance)将费时的操作跑在了新线程中,ObserveOn(this)让后面的观察者跑在了UI线程中。
注:使用ObserveOn(this)需要使用Rx-WinForms
Install-Package Rx-WinForms
这个例子虽然成功了,但是并没有比BeginInvoke(Action action)的方案有明显的进步之处。在一个事件流中再次使用Ovservable.Start()开启新的观察者让人更加摸不着头脑。这并不是Rx的问题,而是事件模型在UI编程中存在局限性:不方便使用异步,不具备可测试性等。以XMAL和MVVM为核心的UI编程模型将在未来处于主导地位,由于在MVVM中可以将UI绑定到一个Command,从而解耦了事件模型。
开源项目ReactiveUI提供了一个以Rx基础的UI编程方案,可以使用在XMAL和MVVM为核心的UI编程中,例如:Xamarin,WFP,Windows Phone8等开发中。
注:在WPF中使用ObserveOn()需要安装Rx-WPF
Install-Package Rx-WPF
3、再来一个例子,让我们感受一下Rx的魅力
界面上有两个Button分别为+和-操作,点击+按钮则+1,点击-按钮则-1,最终的结果显示在一个Label中。
这样的一个需求使用经典事件模型只需要维护一个内部变量,两个按钮的Click事件分别对变量做加1或减1的操作即可。
Rx作为一种函数式编程模型讲求immutable-不可变性,即不使用变量来维护内部状态。
var increasedEventStream = btnIncreasement.FromClickEventPattern() .Select(_ => 1); var decreasedEventStream = btnDecrement.FromClickEventPattern() .Select(_ => -1); increasedEventStream.Merge(decreasedEventStream) .Scan(0,(result,s) => result + s) .Subscribe(x => lblResult.Text = x.ToString());
这个例子使用了IObservable<T>的”谓词”来对事件流做了一些操作。
- Select跟Linq操作有点类似,分别将两个按钮的事件变形为IObservable<int>(1)和IObservable<int>(-1);
- Merge操作将两个事件流合并为一个;
- Scan稍显复杂,对事件流做了一个折叠操作,给定了一个初始值,并通过一个函数来对结果和下一个值进行累加;
下面就让我们来看看IObservable<T>中常用的“谓词”
四、IObservable<T>中的谓词
IObservable<T>的灵感来源于LINQ,所以很多操作也跟LINQ中的操作差不多,例如Where、First、Last、Single、Max、Any。
还有一些“谓词”则是新出现的,例如上面提到的”Merge”、“Scan”等,为了理解这些“谓词”的含义,我们请出一个神器RxSandbox。
1、Merge操作,从下面的图中我们可以清晰的看出Merge操作将三个事件流中的事件合并在了同一个时间轴上。
2、Where操作则是根据指定的条件筛选出事件。
有了这个工具我们可以更加方便的了解这些“谓词”的用途。
五、IObservable<T>的创建
Observable类提供了很多静态方法用来创建IObservable<T>,之前的例子我们都使用FromEventPattern方法来将事件转化为IObservable<T>,接下来再看看别的方法。
Return可以创建一个具体的IObservable<T>:
public static void UsingReturn() { var greeting = Observable.Return("Hello world"); greeting.Subscribe(Console.WriteLine); }
Create也可以创建一个IObservable<T>,并且拥有更加丰富的重载:
public static void UsingCreate() { var greeting = Observable.Create<string>(observer => { observer.OnNext("Hello world"); return disposable.Create(() => Console.WriteLine("Observer has unsubscribed")); }); greeting.Subscribe(Console.WriteLine); }
Range方法可以产生一个指定范围内的IObservable<T>
Observable.Range(1,10) .Subscribe(x => Console.WriteLine(x.ToString()));
Generate方法是一个折叠操作的逆向操作,又称Unfold方法:
public static void UsingGenerate() { var range = Observable.Generate(0,x => x < 10,x => x + 1,x => x); range.Subscribe(Console.WriteLine); }
Interval方法可以每隔一定时间产生一个IObservable<T>:
Observable.Interval(TimeSpan.FromSeconds(1)) .Subscribe(x => Console.WriteLine(x.ToString()));
Subscribe方法有一个重载,可以分别对Observable发生异常和Observable完成定义一个回调函数。
Observable.Range(1,10) .Subscribe(x => Console.WriteLine(x.ToString()),e => Console.WriteLine("Error" + e.Message),() => Console.WriteLine("Completed"));
还可以将IEnumerable<T>转化为IObservable<T>类型:
Enumerable.Range(1,10).ToObservable() .Subscribe(x => Console.WriteLine(x.ToString()));
也可以将IObservable<T>转化为IEnumerable<T>
var list= Observable.Range(1,10).ToEnumerable();
六、Scheduler
Rx的核心是观察者模式和异步,Scheduler正是为异步而生。我们在之前的例子中已经接触过一些具体的Scheduler了,那么他们都具体是做什么的呢?
1、先看下面的代码:
public static void UsingScheduler() { Console.WriteLine("Starting on threadId:{0}",Thread.CurrentThread.ManagedThreadId); var source = Observable.Create<int>( o => { Console.WriteLine("Invoked on threadId:{0}",Thread.CurrentThread.ManagedThreadId); o.OnNext(1); o.OnNext(2); o.OnNext(3); o.OnCompleted(); Console.WriteLine("Finished on threadId:{0}",Thread.CurrentThread.ManagedThreadId); return disposable.Empty; }); source //.SubscribeOn(NewThreadScheduler.Default) //.SubscribeOn(ThreadPoolScheduler.Instance) .Subscribe( o => Console.WriteLine("Received {1} on threadId:{0}",Thread.CurrentThread.ManagedThreadId,o),() => Console.WriteLine("OnCompleted on threadId:{0}",Thread.CurrentThread.ManagedThreadId)); Console.WriteLine("Subscribed on threadId:{0}",Thread.CurrentThread.ManagedThreadId); }
当我们不使用任何Scheduler的时候,整个Rx的观察者和主题都跑在主线程中,也就是说并没有异步执行。正如下面的截图,所有的操作都跑在threadId=1的线程中。
当我们使用SubscribeOn(NewThreadScheduler.Default)或者SubscribeOn(ThreadPoolScheduler.Instance)的时候,观察者和主题都跑在了theadId=3的线程中。
这两个Scheduler的区别在于:NewThreadScheduler用于执行一个长时间的操作,ThreadPoolScheduler用来执行短时间的操作。
2、SubscribeOn和ObserveOn的区别
上面的例子仅仅展示了SubscribeOn()方法,Rx中还有一个ObserveOn()方法。stackoverflow上有一个这样的问题:What's the difference between SubscribeOn and ObserveOn,其中一个简单的例子很好的诠释了这个区别。
public static void DifferenceBetweenSubscribeOnAndobserveOn() { Thread.CurrentThread.Name = "Main"; IScheduler thread1 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread1" }); IScheduler thread2 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread2" }); Observable.Create<int>(o => { Console.WriteLine("Subscribing on " + Thread.CurrentThread.Name); o.OnNext(1); return disposable.Create(() => { }); }) //.SubscribeOn(thread1) //.ObserveOn(thread2) .Subscribe(x => Console.WriteLine("Observing '" + x + "' on " + Thread.CurrentThread.Name)); }
-
当我们注释掉:SubscribeOn(thread1)和ObserveOn(thread2)时的结果如下:
观察者和主题都跑在name为Main的thread中。
-
当我们放开SubscribeOn(thread1):
主题和观察者都跑在了name为Thread1的线程中
-
当我们注释掉:SubscribeOn(thread1),放开ObserveOn(thread2)时的结果如下:
主题跑在name为Main的主线程中,观察者跑在了name=Thread2的线程中。
-
当我们同时放开SubscribeOn(thread1)和ObserveOn(thread2)时的结果如下:
主题跑在name为Thread1的线程中,观察者跑在了name为Thread2的线程中。
至此结论应该非常清晰了:SubscribeOn()和ObserveOn()分别控制着主题和观察者的异步。
七、其他Rx资源
除了.net中的Rx.net,其他语言也纷纷推出了自己的Rx框架。
- RxJS: Javascript中的Rx
- RxCpp:C++中的Rx
- Rx.rb: Ruby中的Rx
- RxPy:python中的Rx
参考资源:
http://rxwiki.wikidot.com/101samples
http://introtorx.com/Content/v1.0.10621.0/01_WhyRx.html#WhyRx
http://www.codeproject.com/Articles/646361/Reactive-Programming-For-NET-And-Csharp-Developers
8 Traits of an Experienced Programmer that every beginner programmer should know
Referrence: http://whats-online.info/guides-and-info/36/Traits-of-Experienced-Programmer-that-every-beginner-should-know/
Not everybody has the capability to be a good programmer. Most lack the desire,others do not have a high level of practical aptitude and others lack the personality required to make a good programmer. To help you understand just what these ‘personality’ traits are,I will break down some of the traits that an experienced programmer has. Being in the field for 8 years Now,believe me I kNow the ups,downs,tricks and ‘’oh no’s’’ in this field. I will take you through 8 crucial traits of a programmer,which can be emulated by the beginners who wanna make it big in this field.
- Consistency
No programmer wants to be the wonder hit-and-disappear kind of a programmer. A good programmer is reliable. He kNows what it is that he wants,and is willing to keep on programming when need be. Not necessarily a 9-5 person,but one who accomplishes tasks and projects without leaving them hanging.
- Problem solver
As a programmer,I would liken programming to solving a complicated mathematics equations. They are complicated and most seem hard to crack. It is easy to just let go of them and look for a simpler equation to tackle. A programmer is that person who doesn’t give up on a task simply because it seems complicated. They look for solutions to every task. Giving up is a phrase that is never heard of in the world of programming.
- Planning skills
To plan is to see ahead. Instead of hopping into a new project,a good programmer will first study as much as he/ she can concerning the anticipated end product. As soon as that analysis is completed,the programmer ought to first strategize the project structure before inputting the first line of code. Planning goes hand in hand with consistency. So a consistent programmer is also a good planner.
- Excellent communication skills
I do not speak the perfect English,but am I good programmer? The answer is yes. Across the years,I have noticed that most of my peers are not fluent English speaker but they do pass for programmers with excellent communication skills. In programming,good communication skills is the ability to express an idea precisely and efficiently. Good programmers are able to pass their points across well. Programmers who experience a tough time conveying their points across or comprehending what others are telling them,may not be successful in the long run.
- Passion for Programming
This is the most important trait of all times. Passion is everything. Without the willingness to work,it will soon or later go down the drain. Some employed programmers only do the 9 to 5 job,for the salary part of it. These caliber of programmers do not program for long because they only do it for the cash,not for the work. When off from work,nothing close to what they do ever crosses their minds. You do not have to wake up,and go to bed breathing codes. Programmers who lack the passion are never enthused to acquire the best method of doing things and instead,they only engage in a routine,which is not be the best technique of doing things.
- Detail Oriented
This is what separates a patient programmer from an impatient one. Programming involves dealing with codes whose simple mistake Could cost you a whole project. A programmer who pays close consideration to detail will be suggestively more industrIoUs than the one who doesn‘t. This trait involves evaluation of self –conscIoUsness,which is very crucial for a serIoUs consistent programmer.
- Ability to cope with changing trends
Technology is constantly changing and the expertise and capabilities a programmer has currently will probably be out-of-date in the coming years. It is,therefore,key for a programmer to be able and willing to educate him/ herself and follow the up-to-date trends. This way,they find it easy to take part in any ongoing education chances that are presented.
- A good reader
A good programmer reads extensively. Not all the work is about coding. A substantial percentage of a programmer‘s work day is spent in reading. It Could be codes typed by other people,Web sites with examples,papers,or projects. Programmers who do not read extensively,or worse,do not comprehend what they are reading,are mostly incompetent at best,and hazardous at worst.
All in all,a good programmer
? Recognizes that programming is a resourceful art and is nothing interesting
? Takes boundless pride in his job and gets abundant contentment from it
? Attempts to decrease the difficulty of both the problem at hand and the result
? He/she utilizes his time but is never too occupied to help others hit the books
? He/she appreciates positive criticism and offers productive criticism for other programmers as well.
? Has Failed countless times but is always willing to learn from the failures.
? Makes his/her decisions without necessarily relying on other people. Sometimes someone needs to make decisions from his/ her heart without the influence of others.
? is continually learning and gets an excitement from those embarrassing moments. nothing is too serIoUs. Laugh at yourself at times.
Programming is not for the faint-hearted. Do not try programming at your desperation when everything else Could not work out. If you possess the above traits that a good programmer should have,then brace yourself for a life changing experience. Above all,hard work is everything.
Cg Programming/ProgrammableGraphics Pipeline
In the following diagrams,there is only one arrow between any two stages.However,it should be understood that GPUs usually implement the graphicspipeline with massive horizontal parallelism. Only software implementations ofthe graphics pipeline,e.g. Mesa 3D (see the Wikipedia entry),usually implement a single pipeline.
The vertex shader and fragment shader stages are discussed in more detail inthe platform-specific tutorials. The rasterization stage is discussed in Section“Rasterization” and theper-fragment operations in Section “Per-FragmentOperations”.
Vertex input parameters are defined based on the vertex data. Foreach vertex input parameter a semantic has to be defined,which specifies how the parameter relates to data in the fixed-functionpipeline. Examples of semantics are POSITION,COLOR,norMAL,TEXCOORD0,TEXCOORD1,etc. This makes it possible to use Cg programs even with APIs that wereoriginally designed for a fixed-function pipeline. For example,the vertexinput parameter for vertex positions should use the POSITION semanticsuch that all APIs can provide the appropriate data for this input parameter.Note that the vertex position is in object coordinates,i.e. this is theposition as specified in a 3D modeling tool.
com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new ReactDrawerLayoutManager(),new ReacthorizontalscrollviewManager(),new ReactimageManager(),new ReactProgressBarViewManager(),new ReactRawTextManager(),new ReactScrollViewManager(),new ReactSwitchManager(),new ReactTextInputManager(),new ReactTextViewManager(),new ReactToolbarManager(),new ReactViewManager(),new ReactViewPagerManager(),new ReactTextInlineImageViewManager(),new ReactVirtualTextViewManager(),new SwipeRefreshLayoutManager(),new ReactWebViewManager()); }
@Override protected void setUp() throws Exception { super.setUp(); List<ViewManager> viewManagers = Arrays.<ViewManager>asList( new ReactViewManager(),new ReactProgressBarViewManager()); mUIManager = new UIManagerModule( getContext(),viewManagers,new UIImplementationProvider(),false); UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { mUIManager.onHostResume(); } }); waitForIdleSync(); mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mUIManager) .addNativeModule(new AndroidInfoModule()) .addNativeModule(new DeviceInfoModule(getContext())) .addNativeModule(new AppStateModule(getContext())) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ProgressBarTestModule.class) .build(); mRootView = new ReactRootView(getContext()); displayMetrics metrics = getContext().getResources().getdisplayMetrics(); mRootView.setLayoutParams( new FrameLayout.LayoutParams(metrics.widthPixels,metrics.heightPixels)); int roottag = mUIManager.addMeasuredRootView(mRootView); mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarapplication(roottag); waitForBridgeAndUIIdle(); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),ARTRenderableViewManager.createARTShapeViewManager(),ARTRenderableViewManager.createARTTextViewManager(),new ARTSurfaceViewManager(),new ReactDialogPickerManager(),new ReactDrawerLayoutManager(),new ReactDropdownPickerManager(),new FrescoBasedReactTextInlineImageViewManager(),new ReactWebViewManager(),new RecyclerViewBackedScrollViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new ReactModalHostManager(),new ReactSliderManager(),new SwipeRefreshLayoutManager()); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( ARTRenderableViewManager.createARTGroupViewManager(),new SwipeRefreshLayoutManager()); }
@Override protected void setUp() throws Exception { super.setUp(); List<ViewManager> viewManagers = Arrays.<ViewManager>asList( new ReactViewManager(),new UIImplementationProvider()); UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { mUIManager.onHostResume(); } }); waitForIdleSync(); mInstance = ReactTestHelper.catalystInstanceBuilder(this) .addNativeModule(mUIManager) .addNativeModule(new AndroidInfoModule()) .addNativeModule(new FakeWebSocketModule()) .addJSModule(ProgressBarTestModule.class) .build(); mRootView = new ReactRootView(getContext()); displayMetrics metrics = getContext().getResources().getdisplayMetrics(); mRootView.setLayoutParams( new FrameLayout.LayoutParams(metrics.widthPixels,metrics.heightPixels)); int roottag = mUIManager.addMeasuredRootView(mRootView); mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarapplication(roottag); waitForBridgeAndUIIdle(); }
@Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { List<ViewManager> viewManagers = new ArrayList<>(); viewManagers.add(ARTRenderableViewManager.createARTGroupViewManager()); viewManagers.add(ARTRenderableViewManager.createARTShapeViewManager()); viewManagers.add(ARTRenderableViewManager.createARTTextViewManager()); viewManagers.add(new ARTSurfaceViewManager()); viewManagers.add(new ReactDialogPickerManager()); viewManagers.add(new ReactDrawerLayoutManager()); viewManagers.add(new ReactDropdownPickerManager()); viewManagers.add(new ReacthorizontalscrollviewManager()); viewManagers.add(new ReactimageManager()); viewManagers.add(new ReactModalHostManager()); viewManagers.add(new ReactProgressBarViewManager()); viewManagers.add(new ReactRawTextManager()); viewManagers.add(new ReactScrollViewManager()); viewManagers.add(new ReactSliderManager()); viewManagers.add(new ReactSwitchManager()); viewManagers.add(new FrescoBasedReactTextInlineImageViewManager()); viewManagers.add(new ReactTextInputManager()); viewManagers.add(new ReactTextViewManager()); viewManagers.add(new ReactToolbarManager()); viewManagers.add(new ReactViewManager()); viewManagers.add(new ReactViewPagerManager()); viewManagers.add(new ReactVirtualTextViewManager()); viewManagers.add(new ReactWebViewManager()); viewManagers.add(new SwipeRefreshLayoutManager()); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(reactContext); if (preferences.getBoolean("flat_uiimplementation",false)) { viewManagers.addAll(Arrays.asList( new RCTViewManager(),new RCTTextManager(),new RCTRawTextManager(),new RCTVirtualTextManager(),new RCTTextInlineImageManager(),new RCtimageViewManager(),new RCTTextInputManager(),new RCTViewPagerManager(),new FlatARTSurfaceViewManager(),new RCTModalHostManager())); } return viewManagers; }
今天关于ReactOS 源码分析 (一) by:ProgrammeBoy和react源码深度解析 慕课网的介绍到此结束,谢谢您的阅读,有关.Net中的反应式编程(Reactive Programming)、8 Traits of an Experienced Programmer that every beginner programmer should know、Cg Programming/ProgrammableGraphics Pipeline、com.facebook.react.views.progressbar.ReactProgressBarViewManager的实例源码等更多相关知识的信息可以在本站进行查询。
本文标签: