F#中的异步和并行设计模式(二):用事件触发来报告进度

CLI工具设计哲学:从瑞幸点单到终端K线图的效率革命 命令行界面(CLI)作为开发者核心的效率工具,其设计哲学正从纯技术领域向消费与金融场景渗透。CLI的本质是通过脚本化与自动化,将复杂操作封装为可编程命令,实现工作流的无缝衔接。这一技术价值在效率至上的开发领域尤为突出,而随着工具生态的演进,优秀的CLI设计开始强调直觉性的命令结构、安全的配置管理与面向机器/人类的双重输出格式。如今,这一理念正驱动着**消费流程的代码化改造**与**专业数据流的终端集成**,例如将点单、编译预览或金融数据可视化等场景融入命令行环境,从而在特定工作流中实现极致的上下文保持与操作 阅读详情

在这篇文章中,我们将着眼于一个常用的异步设计模式,我叫它用事件触发来报告进度。在这篇文章后面,我们将使用这种设计模式从推特上抽样读取帖子流。

这是F#异步编程基础技术系列的第二部分,这里有些例子的代码是摘自F# JAOO 教程。

·        第一部分描述了F# 通过支持轻量级交互是一种怎样的并行和交互式语言,并且介绍了 并行CPU异步处理和并行I/O异步处理模式。

·        第二部分就是这篇文章。

·        第三部分描述了F# 中的轻量级代理、交互式代理、隔离式代理。

模式3:用事件触发来报告进度

让我们先来看看设计模式的本质的一个实例。下面,我们定义一个对象来协调一组asyncs的并行执行。每个工作在它结束时就报告结果,而不是等待结果集。

下面用黄色高亮将设计模式的本质标记出来了:

·        当前“同步的内容”是从对象开始方法的GUI线程抓取的。这是个句柄,它能让我在GUI上下文中运行代码及触发事件。这里定义了一个私有帮助函数来触发任意的F# 事件。严格来说,这不是必须的,但可以让代码更整洁。

·        定义一个或多个事件。这些事件以属性形式发布,如果这个对象将被.Net的其他语言引用的话就标记[<CLIEvent>]。

·        在有后台工作被启动的情况下,通过指定一个异步工作流来定义执行后台工作。Async.Start启动一个工作流的实例(当然Async.StartWithContinuations也会经常被作为替换来使用,本文下面的例子会用到)。这些事件会在后台工作执行的进展中适时地被触发。

下面是方法的示例在这篇文章中,我们将着眼于一个常用的异步设计模式,我叫它用事件触发来报告进度。在这篇文章后面,我们将使用这种设计模式从推特上抽样读取帖子流.

type AsyncWorker<'T>(jobs: seq<Async<'T>>) =   
    // This declares an F# event that we can raise
    let jobCompleted = new Event<int * 'T>()

    /// Start an instance of the work
    member x.Start()   =
        // Capture the synchronization context to allow us to raise events back on the GUI thread
        let syncContext = SynchronizationContext.CaptureCurrent()
 
        // Mark up the jobs with numbers
        let jobs = jobs |> Seq.mapi (fun i job-> (job,i+1))  
        let work = 
            Async.Parallel
               [ for (job,jobNumber) in jobs->
                  async { let! result = job
                          syncContext.RaiseEvent jobCompleted (jobNumber,result)
                          return result } ]
 
        Async.Start(work |> Async.Ignore)

    /// Raised when a particular job completes
    member x.JobCompleted = jobCompleted.Publish

这里的代码使用两个在System.Threading.SynchronizationContext命名空间的帮助扩展方法,在这系列的文章中,我们会经常使用到。下面是方法的示例:

type SynchronizationContextwith
    /// A standard helper extension method to raise an event on the GUI thread
    member syncContext.RaiseEvent (event: Event<_>) args =
        syncContext.Post((fun _-> event.Trigger args),state=null)
 
    /// A standard helper extension method to capture the current synchronization context.
    /// If none is present, use a context that executes work in the thread pool.
    staticmember CaptureCurrent () =
        match SynchronizationContext.Currentwith
        |null -> new SynchronizationContext()
        | ctxt-> ctxt
现在你能用这个组件来监督CPU密集的异步线程集合的执行:

    letrec fib i = if i <2 then 1 else fib (i-1) + fib (i-2)    
    let worker =
        new AsyncWorker<_>( [ for i in 1 .. 100-> async { return fib (i %40) } ] )
 
    worker.JobCompleted.Add(fun (jobNumber, result)->
        printfn "job %d completed with result %A" jobNumber result)

    worker.Start()  
当运行时,每个工作完成后,程序都会报告进度: 
job 1 completed with result 1
job 2 completed with result 2
...
job 39 completed with result 102334155
job 77 completed with result 39088169
job 79 completed with result 102334155
当然从后台进程获取结果报告有许多方法。 百分之九十的情况下,最简单的方法就如上面展示的那样:通过在GUI(或者ASP.NET页面加载)线程上触发.NET事件来报告结果。 这个技术完全隐藏了后台线程的使用,采用完全标准的任何.NET程序员都熟悉的.NET习俗。这确保了用来实现你并行编程的这项技术被适当的封装了。
报告I/O异步处理的进度
用事件触发来报告进度模式当然也能同I/O异步一同使用。例如,下面一系列的I/O任务:

    open System.IO
    open System.Net
    open Microsoft.FSharp.Control.WebExtensions  
    /// Fetch the contents of a web page, asynchronously.
    let httpAsync(url:string) =
        async { let req = WebRequest.Create(url)
                use! resp = req.AsyncGetResponse()
                use stream = resp.GetResponseStream()
                use reader = new StreamReader(stream)
                let text = reader.ReadToEnd()
                return text }

    let urls =
        [ "http://www.live.com";
          "http://news.live.com";
          "http://www.yahoo.com";
          "http://news.yahoo.com";
          "http://www.google.com";
          "http://news.google.com"; ]
 
    let jobs =  [for url in urls -> httpAsync url ]
   
    let worker =new AsyncWorker<_>(jobs)
    worker.JobCompleted.Add(fun (jobNumber, result)->
        printfn "job %d completed with result %A" jobNumber result.Length)
 
    worker.Start()
当代码运行,会逐步地报告结果,显示每个网页的长度: 
job 5 completed with result 8521
job 6 completed with result 155767
job 3 completed with result 117778
job 1 completed with result 16490
job 4 completed with result 175186
job 2 completed with result 70362
一些工作会报告多种不同的事件
在这种设计模式中,我们用一个对象来封装和监控并行组合的异步线程的执行,其中的一个理由是它让通过进一步的事件来丰富(有更多)监督进度的API变得更简单。例如, 下面代码会在所有工作都完成以后,或者在任何一个工作中检测到错误时,或者在整个程序完成前被成功取消时触发额外的事件。下面高亮部分显示了事件的定义、事件的触发和事件的发布。 
open System
open System.Threading
open System.IO
open Microsoft.FSharp.Control.WebExtensions
 
type AsyncWorker<'T>(jobs: seq<Async<'T>>) =
     // Each of these lines declares an F# event that we can raise
    let allCompleted  = new Event<'T[]>()
    let error         = new Event<System.Exception>()
    let canceled      = new Event<System.OperationCanceledException>()
    let jobCompleted  = new Event<int * 'T>()
 
    let cancellationCapability =new CancellationTokenSource()
 
    /// Start an instance of the work
    member x.Start()    =                                                                                                               
        // Capture the synchronization context to allow us to  raise events back on the GUI thread
        let syncContext = SynchronizationContext.CaptureCurrent()
        // Mark up the jobs with numbers

        let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1))

        let work = 
            Async.Parallel
               [ for (job,jobNumber) in jobs ->
                   async { let! result = job
                           syncContext.RaiseEvent jobCompleted (jobNumber,result)
                           return result } ]
 
        Async.StartWithContinuations
            ( work,
              (fun res-> raiseEventOnGuiThread allCompleted res),
              (fun exn-> raiseEventOnGuiThread error exn),
              (fun exn-> raiseEventOnGuiThread canceled exn ),
             cancellationCapability.Token)
 
    member x.CancelAsync() =
       cancellationCapability.Cancel()
       
    /// Raised when a particular job completes
    member x.JobCompleted  = jobCompleted.Publish
    /// Raised when all jobs complete
    member x.AllCompleted  = allCompleted.Publish
    /// Raised when the composition is cancelled successfully
    member x.Canceled   = canceled.Publish
    /// Raised when the composition exhibits an error
    member x.Error      = error.Publish  
 我们可以用通常的方法来使用这些额外的事件,例如:

    let worker =new AsyncWorker<_>(jobs)  
    worker.JobCompleted.Add(fun (jobNumber, result)->
        printfn "job %d completed with result %A" jobNumber result.Length)

    worker.AllCompleted.Add(fun results->
        printfn "all done, results = %A" results )  
    worker.Start()
这个监督异步工作流能支持取消操作,就像上面例子列出的。
Tweet Tweet, Tweet Tweet(一个WordPress的插件)
用事件触发来报告进度模式可以应用到几乎任何的后台处理组件来进行结果报告。下面的例子,我们将用这个模式来封装从后台读取的来自推特的文章数据流(参考推特 API页面)。这里例子需要一个推特的账号和密码。这个例子中只有一个事件被触发,当然这个例子可以扩展成其他情况下触发其他的事件。
F# JAOO 教程包含了这个例子的一个版本。
// F# Twitter Feed Sample using F# Async Programming and Event processing
#r "System.Web.dll"
#r "System.Windows.Forms.dll"
#r "System.Xml.dll"
 
open System
open System.Globalization
open System.IO
open System.Net
open System.Web
open System.Threading
open Microsoft.FSharp.Control.WebExtensions
 
/// A component which listens to tweets in the background and raises an
/// event each time a tweet is observed
type TwitterStreamSample(userName:string, password:string) =
 
    let tweetEvent = new Event<_>()  
    let streamSampleUrl ="http://stream.twitter.com/1/statuses/sample.xml?delimited=length"
 
    /// The cancellation condition
    letmutable group = new CancellationTokenSource()
 
    /// Start listening to a stream of tweets
    member this.StartListening() = 
        /// The background process
        // Capture the synchronization context to allow us to  raise events back on the GUI thread
        let syncContext = SynchronizationContext.CaptureCurrent()
 
        let listener (syncContext: SynchronizationContext) =
            async { let credentials = NetworkCredential(userName, password)
                    let req = WebRequest.Create(streamSampleUrl, Credentials=credentials)
                    use! resp = req.AsyncGetResponse()
                    use stream = resp.GetResponseStream()
                    use reader = new StreamReader(stream)
                    let atEnd = reader.EndOfStream
                    let rec loop() =
                        async {
                            let atEnd = reader.EndOfStream
                            if not atEnd then
                               let sizeLine = reader.ReadLine()
                                if String.IsNullOrEmpty sizeLine then return! loop() else
                               let size = int sizeLine
                               let buffer = Array.zeroCreate size
                               let _numRead = reader.ReadBlock(buffer,0,size) 
                               let text = new System.String(buffer)
                                syncContext.RaiseEvent tweetEvent text
                               return! loop()
                        }
                    return! loop() }
 
        Async.Start(listener, group.Token)
 
    /// Stop listening to a stream of tweets
    member this.StopListening() =
        group.Cancel();
        group <- new CancellationTokenSource()
 
    /// Raised when the XML for a tweet arrives
    member this.NewTweet = tweetEvent.Publish
每次从推特的标准采样信息流产生一个信息时会触发一个事件,然后提供该帖子的内容。我们可以用以下代码来监听这个数据流:
let userName ="..." // set Twitter user name here
let password ="..." // set Twitter user name here  
let twitterStream =new TwitterStreamSample(userName, password)

twitterStream.NewTweet
   |> Event.add (fun s-> printfn "%A" s)  
twitterStream.StartListening()
twitterStream.StopListening()
当这段代码运行时,将打印出一个的原始XML信息流(非常地快)。参考推特API
来了解这信息流是怎样采样的。
如果你想解析这些信息,这里有一些示例代码实现了类似的功能(当然也请注意推特 API页面上的指导,例如,如果想建立一个高可靠性的系统,这些信息必须在处理前经常的被保存或进行排队)。

#r"System.Xml.dll"
#r"System.Xml.Linq.dll"
open System.Xml
open System.Xml.Linq 
let xn (s:string) = XName.op_Implicit s

/// The results of the parsed tweet
type UserStatus =
    { UserName : string
      ProfileImage : string
      Status : string
      StatusDate : DateTime }

/// Attempt to parse a tweet
let parseTweet (xml: string) =  
    let document = XDocument.Parse xml

    let node = document.Root
    if node.Element(xn"user") <> nullthen
        Some { UserName     = node.Element(xn"user").Element(xn "screen_name").Value;
               ProfileImage = node.Element(xn"user").Element(xn "profile_image_url").Value;
               Status       = node.Element(xn"text").Value       |> HttpUtility.HtmlDecode;
               StatusDate   = node.Element(xn"created_at").Value |> (fun msg->
                                  DateTime.ParseExact(msg,"ddd MMM dd HH:mm:ss +0000 yyyy",
                                                       CultureInfo.CurrentCulture)); }
    else
        None
然后组合子编程能被用来对该数据流进行管道化处理: 
twitterStream.NewTweet
   |> Event.choose parseTweet
   |> Event.add (fun s-> printfn "%A" s)
 
twitterStream.StartListening()

再从该数据流中进行统计: 
let addToMultiMap key x multiMap =
   let prev =match Map.tryFind key multiMap with None -> [] | Some v -> v
   Map.add x.UserName (x::prev) multiMap
 
/// An event which triggers on every 'n' triggers of the input event
let every n (ev:IEvent<_>) =
   let out =new Event<_>()
   let count = ref0
   ev.Add (fun arg-> incr count; if !count % n =0 then out.Trigger arg)
   out.Publish
 
twitterStream.NewTweet
   |> Event.choose parseTweet
   // Build up the table of tweets indexed by user
   |> Event.scan (fun z x-> addToMultiMap x.UserName x z) Map.empty
   // Take every 20’th index
   |> every 20
   // Listen and display the average of #tweets/user
   |> Event.add (fun s->
        let avg = s |> Seq.averageBy (fun (KeyValue(_,d))-> float d.Length)
        printfn "#users = %d, avg tweets = %g" s.Count avg)
 
twitterStream.StartListening()

这里的示例数据流根据用户来进行索引,显示每个用户的平均发言量,每成功解析20个发言就进行一次结果报告

 

#users = 19, avg tweets = 1.05263
#users = 39, avg tweets = 1.02564
#users = 59, avg tweets = 1.01695
#users = 79, avg tweets = 1.01266
#users = 99, avg tweets = 1.0101
#users = 118, avg tweets = 1.01695
#users = 138, avg tweets = 1.01449
#users = 158, avg tweets = 1.01266
#users = 178, avg tweets = 1.01124
#users = 198, avg tweets = 1.0101
#users = 218, avg tweets = 1.00917
#users = 237, avg tweets = 1.01266
#users = 257, avg tweets = 1.01167
#users = 277, avg tweets = 1.01083
#users = 297, avg tweets = 1.0101
#users = 317, avg tweets = 1.00946
#users = 337, avg tweets = 1.0089
#users = 357, avg tweets = 1.0084
#users = 377, avg tweets = 1.00796
#users = 396, avg tweets = 1.0101
#users = 416, avg tweets = 1.00962
#users = 435, avg tweets = 1.01149
#users = 455, avg tweets = 1.01099
#users = 474, avg tweets = 1.01266
#users = 494, avg tweets = 1.01215
#users = 514, avg tweets = 1.01167
#users = 534, avg tweets = 1.01124
#users = 554, avg tweets = 1.01083
#users = 574, avg tweets = 1.01045
#users = 594, avg tweets = 1.0101
 
通过稍微不同的解析,我们可以根据推特提供的采样信息流来显示那些发言超过一次的用户(包括他们的最后一次发言)。这里将在F# Interactive上交互式地执行,并且使用上篇文章的F# Interactive 数据表格片段试图:

open System.Drawing
open System.Windows.Forms 
let form = new Form(Visible = true, Text = "A Simple F# Form", TopMost = true, Size = Size(600,600))

let data = new DataGridView(Dock = DockStyle.Fill, Text = "F# Programming is Fun!",
                            Font = new Font("Lucida Console",12.0f),
                            ForeColor = Color.DarkBlue) 
form.Controls.Add(data)
 
data.DataSource <- [| (10,10,10) |]

data.Columns.[0].Width <- 200
data.Columns.[2].Width <- 500
 
twitterStream.NewTweet
   |> Event.choose parseTweet
   // Build up the table of tweets indexed by user
   |> Event.scan (fun z x -> addToMultiMap x.UserName x z) Map.empty
   // Take every 20’th index
   |> every 20
   // Listen and display those with more than one tweet
   |> Event.add (fun s ->
        let moreThanOneMessage = s |> Seq.filter (fun (KeyValue(_,d)) -> d.Length > 1) 
        data.DataSource <- 
            moreThanOneMessage
            |> Seq.map (fun (KeyValue(user,d)) -> (user, d.Length, d.Head.Status))
            |> Seq.filter (fun (_,n,_) -> n > 1)
            |> Seq.sortBy (fun (_,n,_) -> -n)
            |> Seq.toArray)
 
twitterStream.StartListening() 
这里是一些示例结果:
注意:在上面的例子中,我们使用I/O中断来读取推特信息流。这么做有两个充足的理由:推特信息流是非常活跃的(有时候可能会有信息残留J),我们也可以假设在这许多的推特信息流中有许多未完成的链接,在这种情况只有一个链接,而在任何情况下推特都会限制每个账户监听采样信息流的次数。在下一篇文章中,我们将展示怎么做无中断的读取这种格式的XML信息流。
F# 做并行处理,C#/VB做GUI
用事件触发来报告进度模式在下面这种情况下非常有用,F#程序员实现基于某些输入的后台计算组件,C#或VB程序员使用这些组件。在这种情况下,事件的声明必须用[<CLIEvent>]标记来强调它们作为.NET事件出现(对C#或VB程序员而言)。在上面第二个例子中,你将使用 
    /// Raised when a particular job completes
    [<CLIEvent>]
    member x.JobCompleted  = jobCompleted.Publish 
    /// Raised when all jobs complete
    [<CLIEvent>]
    member x.AllCompleted  = allCompleted.Publish

    /// Raised when the composition is cancelled successfully
    [<CLIEvent>]
    member x.Canceled   = canceled.Publish

    /// Raised when the composition exhibits an error
    [<CLIEvent>]
    member x.Error      = error.Publish 
该模式的限制
用事件触发来报告进度模式是假设在以下情况下的:一个并行处理组件运行在一个GUI应用程序(如Windows Forms)、服务端应用程序(如ASP.NET)或者一些可以触发事件后发回给监听端的程序。这里可以通过调整这个模式来用其他方式触发事件,例如, 发送一个消息到MailBoxProcessor或简单地记录它们。然而要注意的是这个模式还有一个假设:已经有一些主线程或者监听端准备好在任意时刻监听这些事件并且合理地对它们进行排队。
用事件触发来报告进度模式也假设这个封装的对象有能力获取GUI线程的同步内容,正常情况是隐式地(就如上面的例子)。 这通常是一个合理的假设。另外,这些同步内容也可以作为一个显式的参数给出,虽然这不是一个非常普遍的.NET编程习惯。
对那些熟悉IObservable接口(.NET4.0中新增)的程序员,可以考虑用TwitterStreamSample类型来实现这个接口。 然而对于事件的根源,没必要了解那么多。例如, 在将来TwitterStreamSample或许会提供多个事件:当错误发生时报告自动重新连接,或报告中断与延迟。在这情况下,简单地触发.NET事件就足够了,部分地确保你的对象对大部分.NET程序员 来说是熟悉的。在F# 中,所有声明的IEvent<_>值都是自动实现IObservable接口的,所以能直接的用于可观察的组合程序。
结论
用事件触发来报告进度是一种用来封装后台并行处理,同时能够报告结果和进度的强大和优雅的方法。
从表面看,AsyncWorker对象就像单线程一样地效率。 假使你输入的asyncs是隔离的,这意味着组件不会使你程序的其余部分处于多线程的竞争条件下。所有的Javascript框架、ASP.NET框架和GUI框架(如Windows Forms)的用户知道这些框架的单线程形式既是一种祝福也是一种诅咒——你获得了简单(没有数据冲突),但是在.NET编程中并行和异步编程比较困难,I/O和繁重的CPU计算被卸载到了后台线程。 上面的设计模式让你从两边都做到最好:你获得了独立的、能协作的、能“交流的”后台处理组件(包括那些并行处理和I/O),同时又达到了使你大部分代码像单线程GUI编程那样简单。这些组件能被泛型化和重复使用,就像上面展示的那样。这使得它们适合于独立的单元测试。
在以后的文章中,我们将讨论另外的关于F# 异步的并行和交互式编程的一些设计话题,其中包括:
Ø 定义轻量级异步代理
Ø 用异步创建.NET任务
Ø 用异步创建.NET APM模式
Ø 异步取消
 
原文链接:http://blogs.msdn.com/b/dsyme/archive/2010/01/10/async-and-parallel-design-patterns-in-f-reporting-progress-with-events-plus-twitter-sample.aspx
 
你也可以联系F#QQ群:61436709
.NET Framework 1.0到4.0底层演进:CLR、泛型、LINQ与并发模型的技术脉络 .NET Framework 是微软构建的统一托管运行时平台,其核心在于公共语言运行时(CLR)对内存管理、线程调度与类型系统的深度控制。从1.0初代寄生式设计,到2.0引入分代垃圾回收与泛型支持,再到3.5依托表达式树实现LINQ声明式查询,最终在4.0完成IOCP线程池与Task并行库的工程落地——这一演进本质是运行时能力持续解耦、强化与标准化的过程。它奠定了现代.NET跨平台、高性能与安全隔离的技术根基,广泛应用于企业级Web服务、桌面应用及混合部署系统。理解CLR版本差异、泛型JIT特化机制与LIN 阅读详情

相关推荐

FSharp.AsyncExtensions:[已归档] F# 中异步编程的扩展

注意:此项目不再维护。 请改为使用/贡献以下两个项目: 包含异步序列 包含来自此 repo 的其他帮助程序(代理、 AwaitObservable等) 我将这个 repo 以其原始形式留在这里,以防这里还有其他东西没有移到别处,但我不会接受拉取请求或以任何方式维护它。 F# 异步扩展 [已归档] 该库使用 F# 异步工作流和 F# 代理(标准 F# 库中的MailboxProcessor类型)为异步编程实现了各种扩展。 它定义了异步序列,表示返回多个值的异步操作(例如从块中读取流中的数据)、几个可重用的 F# 代理和许多扩展。 可以在找到演示如何使用大多数扩展的 异步序列 异步序列可用于处理返回多个结果的异步计算。 可以启动AsyncSeq<'T>类型的值(就像异步工作流一样)并最终返回。 结果要么是一个表示序列结束的特殊值,要么是一个类型为'T (头)的值以及类型为AsyncSe

F#语言的多线程编程

多线程编程是一种能够在同一程序中同时运行多个线程的编程方法。线程是操作系统能够独立调度的基本单位,是轻量级的进程。通过多线程,程序可以同时处理多个任务,从而提高资源利用率和运行效率。在多核处理器日益普及的今天,多线程编程的重要性愈加突出。F#是一种基于.NET平台的功能编程语言,具有强大的类型推导机制、不可变数据结构,以及对并发和异步编程的良好支持。F#与C#等其他.NET语言的结合,使得它能够轻松地使用来自.NET生态系统的丰富类库。

2501_90291103的博客 441

ROS基础(一)——命令行代码(以小乌龟程序为例)

ROS学习(一)——命令行代码(以小乌龟程序为例)1 基础命令行语句1.1 roscore1.2 rqt_graph(显示系统计算图)1.3 rosnode(显示所有节点相关信息)1.4 rostopic(和话题相关)2 服务类型指令rosservice同时存在两只海龟3 指令记录 1 基础命令行语句 从大二四旋翼无人机编队后就没再接触过ROS了,最近由于科研任务需要重新捡起来,打算系统学一下!学习过程参考古月居老师的视频,有兴趣的同学可以去[BliBli]学习。 学习平台:Ubuntu 18.04 硬件

北理自动化小白 6267

【F#】核心数据多线程处理的首选

http://www.cnblogs.com/zilin-xiao/archive/2011/08/26/2155124.html 转载于:https://www.cnblogs.com/viewcozy/p/4624413.html

weixin_30600503的博客 138

群晖NAS从入门到精通的所有帖子汇总,只要这一篇就够了

本站陆陆续续的转载、原创帖子也有十几二十篇了,从不同的角度对群晖NAS的各种骚操作都有深入的讲解,虽然很多文章都不是讲的很深入,但是针对小白入门已经是足够了,希望对小白来说是一个入门,群晖NAS的大佬们勿喷,哪里写的不对的,请随时留言西安SEO优化站长一定在第一时间纠正修改。

西安SEO优化网站资源 8万+

软考29-上午题-【数据结构】-排序

数据结构7种排序

qq_31532983的博客 1579

同步、异步、多线程与事件型综述

同步、异步、多线程与事件型综述 作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs首先要了解什么是阻塞和阻塞式IO。线程在执行中如果遇到磁盘读写或网络通信(统称IO操作),通常要耗费较长的时间,这时操作系统会剥夺此线程的CPU控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。当IO操作完毕时,操作系统将这个线程的阻塞状态解除,恢...

海瑟天涯 222

SimMechanics二连杆仿真避坑指南:Solid模块坐标系设置与Rigid Transform常见错误

本文详细解析了SimMechanics中二连杆平面臂仿真的常见问题,重点探讨Solid模块坐标系设置与Rigid Transform模块的配置陷阱。通过实战案例和MATLAB代码示例,揭示多体系统仿真中的关键错误点,包括坐标系方向定义、参数匹配、端口连接规则等,帮助工程师有效规避仿真风险,提升建模效率。

weixin_29309213的博客 412

F#中的异步及并行模式(3 - 下):代理的进一步使用

在本系列的第3部分中,我们会来探索F#中轻量级的,交互式的代理,以及与代理有关的一些模式,包括隔离的内部状态。(译注:由于原文内容较多,译文拆成两段进行。在上半段文章中讨论了代理的基本使用方式,而下半段则讨论关于代理使用中更进一步的模式。) 消息与联合类型 很多时候我们会使用联合类型(Union Type)作为消息的类型。例如,我将要展示一个基于代理的DirectX示例,我们要在模拟引擎中...

weixin_34067102的博客 166

2026年数据中心运行与管理专业人才培养基地建设方案(高职、数据中心运行与管理新专业、人才培养、专业代码:510310)

摘要: 为响应国家“东数西算”战略和数字经济需求,我校拟联合行业领军企业建设数据中心运行与管理人才培养基地。项目基于国家政策引导和产业快速发展背景,针对行业10万人才缺口,对标教育部新设专业标准(510310),分三阶段实施五年规划:专业奠基(2026-2028)、内涵深化(2028-2029)、辐射引领(2030-2031)。建设内容涵盖校企协同岗位能力分析、模块化课程开发(如网络管理、自动化运维等)、实训基地搭建及“课证融通”培养模式,重点培养基础设施、网络服务、运维托管三类岗位技能人才,目标建成区域性

啊碧根果的博客 1685

【LAMMPS学习】八、基础知识(4.5)TIP5P水模型

​ 五点 TIP5P 刚性水模型通过添加两个通常无质量的附加位点 L 来扩展three-point TIP3P model,其中放置与氧原子相关的电荷。这些位点 L 位于距氧原子固定距离处,形成从 HOH 平面旋转 90 度的四面角。因此,这些位点在某种程度上近似于氧的孤对,从而改善了水结构,与four-point TIP4P model相比变得更加“四面体”。

荷塘阅色 1421

LibrePhotos批量导入工具:处理 thousands 张照片的效率优化

# LibrePhotos批量导入工具:处理 thousands 张照片的效率优化 ## 引言:摄影爱好者的数字噩梦 你是否经历过这样的场景:旅行归来,存储卡里塞满了上千张照片,导入电脑后却陷入整理的泥潭?手动分类、重复检测、元数据提取——这些耗时费力的工作足以磨灭任何人的创作热情。作为一款自托管的开源照片管理系统(Self-hosted Open Source Photo Managemen...

gitblog_01180的博客 489

基于YOLOv5的人脸识别系统:从构建到应用的全流程指南

本文详细介绍了基于YOLOv5的人脸识别系统开发全流程。首先阐述了YOLOv5模型的高效性和准确性优势,随后分步骤讲解了深度学习环境配置、数据集准备(推荐WIDER FACE数据集)和模型训练方法。重点展示了如何将训练好的模型集成到Tkinter开发的GUI界面中,实现图片上传、人脸检测和结果可视化功能。文章提供完整的代码示例和飞书文档链接(密码:946m22&8),帮助开发者快速构建可交互的人脸识别系统,适用于安防、门禁等多种应用场景。通过该项目,读者可掌握YOLOv5的实际应用和界面集成技术。

FJN110的博客 169

基于事件的异步模式概述

那些同时执行多项任务、但仍能响应用户交互的应用程序通常需要实施一种使用多线程的设计方案。 System.Threading 命名空间提供了创建高性能多线程应用程序所必需的所有工具,但要想有效地使用这些工具,需要有丰富的使用多线程软件工程的经验。 对于相对简单的多线程应用程序,BackgroundWorker 组件提供了一个简单的解决方案。 对于更复杂的异步应用程序,请考虑实现一个符合基于事件的异步

chlyzone 899

[STC32G144K246入门第一步]点亮LED

STC32G144K246是一款高性能32位8051单片机,集成了丰富外设资源,适用于工业控制和复杂算法处理。该芯片支持双模式内核,内置硬件加速器,提供246KB Flash和144KB SRAM存储空间。文章详细介绍了开发环境搭建步骤、寄存器配置方法,并给出了LED驱动示例代码,通过推挽输出控制P42口实现闪烁效果。虽然开发环境相比ARM存在不足,但通过合理配置仍可满足项目需求。该教程为开发者快速上手STC32G144K246提供了实用参考。

sinat_58149788的博客 799

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

同步 异步和事件

同步和异步 事件 浏览器提供了同步和异步机制 JS是单线程的,提供了两个队列,一个是主队列(放同步代码),一个是异步队列队列池。 同步 所有的代码按顺序执行,每一部分执行完后才能执行下面的代码。 异步 这块代码执行后,可以去做其他事情,等这块代码执行完后,再回来处理这里的事项。 异步性能会比较高 回调函数 ajax 定时器 时间 ...

a404007652的博客 879

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

异步事件 同步事件

来源:http://www.blogjava.net/cj78go/archive/2006/09/19/70525.html 知道什么叫同步和异步吗? In synchronous receiving, while the server is waiting to receive data from a client, if the stream is empty the main th

xiaocaichonga的专栏 4930

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

setState的异步,同步以及合并

setState <body> <div id="test"></div> </body> <!-- 核心库 --> <script type="text/javascript" src="js/react.development.js"></script> <!-- 基于React专门用于操作DOM的扩展库 --> <script type="text/javascript" src="js/re

weixin_44492275的博客 572

JS中的异步以及事件轮询机制

一、JS为何是单线程的?      JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。(在JAVA和c#中的异步均是通过多线程实现的,没有循环队列一说,直接在子线程中完成相关的操作)      JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动

heshan1992的博客 7144

JavaScript:同步、异步和事件循环

一. 单线程 我们常说“JavaScript是单线程的”。 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。 但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们工作线程。...

weixin_30487317的博客 445

《.NET并发编程实战》之 函数式并发基础

本书是一本划时代的著作!在以下领域具有非常深远的意义: .NET 开发领域——本书再次将.NET 开发人员进行了分层隔代。 高性能/多核/并发编程领域——本书让锁从此变成过去时。 程序员职业生涯领域——本书让普通程序员得以和数学进行接驳。 本书在.NET 开发领域中的意义 作为广州.NET 技术俱乐部主席、中国香港Azure/.NET 技术俱乐部创始人兼 主席、.NET 社区联盟建设者,我对大中华区的.NET 开发人员现状有一定的了解。 目前,虽然.NET 开发人员很多,但因为.NET 至今已存在了..

清图出版 5298

多线程摘录 003

同步器A synchronizer is any object that coordinates the control flow of threads based on its state. Blocking queues can act as synchronizers; other types of synchronizers include semaphores, barriers, a...

Chinaxxren 154

F#试用感受

花了一晚上,来摸索了F#,虽然以前接触过很多次,但是心里还是比较抵触,总感觉有些设计不太合理 1 没有块的结束符,使用太多的空格,缩进来表示一个整体。这个简直让人发疯。我们经常从网络或文献里找到关键代码,弄下来之后,格式已经和原版变得面目全非。有不少编辑器自动换行,而F#用空格来界定,难以接受。 2 一开头就有个let,有点恶心。跟学basic一样,就因为basic有个let,所以一直就没有用...

weixin_34090562的博客 496

.NET编程语言新成员:F#

  .NET编程语言新成员:F# 函数式编程语言拥有很长的历史,但大多局限于学术界使用,直到Visual Studio 2010中新添加了F#,才使函数式编程开始走向真正的商业应用。 Visual Studio 2010为F#提供了方便和强大的编辑手段,只需在代码编辑器中选中要执行的F#语句, 按Alt+Enter组合键,就可以直接在Visual Studio 2010集成的F#

in permanent beta... 700
上一篇: 设计模似和F#相关资料的一些链接
下一篇: F#中的异步和并行设计模式(三):代理
fsharp_net
博客等级 码龄15年 20粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值