接下来再赋值,有个别地点不佳翻译的地点会用

2019-09-23 作者:编程   |   浏览(64)

接上文多线程编程学习笔记——线程同步

一、前言

最近做的项目使用WebApi,采取前后端分离的方式,后台提供API接口给前端开发人员。这个过程中遇到一个问题后台开发人员怎么提供接口说明文档给前端开发人员,最初打算使用wordXmind思维导图方式进行交流,实际操作中却很少动手去写。为了解决这个问题,特意在博客园搜索了一下api接口文档生成的文章,引起我注意的有以下两种方案。

  • 微软自带的Microsoft.AspNet.WebApi.HelpPage
  • Swagger

但是在使用过程中微软自带的没有Swagger直观,因此采用了第二种方案Swagger

NSString和NSMutableString都是对象类型,是NSObject的子类。NSString是不可变字符串,NSMutableString是可变字符串

目录

    1. 写在前面的话
    1. 介绍
    1. 代码组织
    • 3.1. 工作区
    • 3.2. GOPATH 环境变量
    • 3.3. Package 路径
    • 3.4. 第一个 GO 程序
    • 3.5. 第一个 GO 库
    • 3.6. Package name
    1. 测试
    1. 远程 package
    1. 下一步
    1. 获取帮助

四、使用AutoResetEvent

1. 使用AutoResetEvent类来实现从一个线程向另一个线程发出通知。

2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics;namespace ThreadSynchronousDemo{    class Program    {        static AutoResetEvent autoResetWork = new AutoResetEvent(false);        static AutoResetEvent autoResetMain = new AutoResetEvent(false);        static void Main(string[] args)        {            Console.WriteLine("开始,AutoResetEvent 同步");                       string threadName = "线程 1";                         var t = new Thread => working(threadName, 10)));                t.Start();            Console.WriteLine("开始,第一次工作");             autoResetWork.WaitOne();//万事俱备只欠东风,事情卡在这里了,            Console.WriteLine("第一次工作完成");            Console.WriteLine("主线程操作,准备发信号");            Thread.Sleep(TimeSpan.FromSeconds(5));            //发信号,说明值已经被写进去了。这里的意思是说Set是一个发信号的方法。            autoResetMain.Set();            Console.WriteLine("现在运行第二次工作。");            autoResetWork.WaitOne();            Console.WriteLine("第二次工作完成");            Console.Read();        }         static void working(string name,int seconds)        {            Console.WriteLine("{0} 开始运行工作", name);            Thread.Sleep(TimeSpan.FromSeconds;            Console.WriteLine("{0}  正在工作。。。。。。",              name);            //发信号,说明值已经被写进去了。这里的意思是说Set是一个发信号的方法。            autoResetWork.Set();            Console.WriteLine("等待主线程完成工作,并发出信号");            autoResetMain.WaitOne();            Console.WriteLine("主线程发来信号,开始第二次工作");            Thread.Sleep(TimeSpan.FromSeconds;            Console.WriteLine("{0} 第二次工作正在进行中。。。。。", name);            autoResetWork.Set();        }    }} 

3.程序运行结果,如下图。

图片 1

以上程序中,我们定义了两个AutoResetEvent实例。其中一个是从子线程往主线程发信号 ,另一个是主线程往子线程发信号。我们在构造AutoResetEvent时,传入了false,定义了这两个实例的初始状态unsignaled。这个状态下,任何线程调用这两个实例的WaitOne方法将会被阻塞,直到我们调用了Set方法。如果我们在构造的时候传入了true,则这两个实例的初始状态是singnaled,则线程调用WaitOne则会被立即处理。

五、使用ManualResetEventSlim类

1. 使用ManualResetEventSlim在线程间传递信号。

2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics; namespace ThreadSynchronousDemo{    class Program    {        static ManualResetEventSlim manuResetWork = new ManualResetEventSlim(false);              static void Main(string[] args)        {            Console.WriteLine("开始,ManualResetEventSlim 同步");                       string threadName = "线程 1";            string threadName2 = "线程 2";             string threadName3 = "线程 3";            var t = new Thread => working(threadName, 3)));            var t2 = new Thread => working(threadName2, 6)));            var t3 = new Thread => working(threadName3, 12)));            t.Start();            t2.Start();            t3.Start();            Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine("开始,打开 线程工作大门");            manuResetWork.Set(); //发信号            Thread.Sleep(TimeSpan.FromSeconds(3));            manuResetWork.Reset();                       Console.WriteLine("线程工作大门,关闭");                     Thread.Sleep(TimeSpan.FromSeconds(10));            Console.WriteLine("打开线程工作大门第二次打开了");            manuResetWork.Set(); //发信号            Thread.Sleep(TimeSpan.FromSeconds(3));            manuResetWork.Reset();            Console.WriteLine("线程工作大门,又关闭了");            Console.Read();        }        static void working(string name,int seconds)        {            Console.WriteLine("{0} 休息", name);            Thread.Sleep(TimeSpan.FromSeconds;            Console.WriteLine("{0}  等待打开线程运行的大门",              name);            manuResetWork.Wait();            Console.WriteLine("线程运行的大门打开了,{0} 进行工作", name);               }    }}

3.程序运行结果,如下图。

图片 2

当主程序启动时,首先创建ManualResetEvenSlim类的一个实例,然后启动了三个线程,等待事件信号通知它们继续工作。

ManualResetEvenSlim的工作方式有点像人群通过大门,而AutoResetEvent事件像一个旋转门,一次只能通过一人。

ManualResetEvenSlim打开了大门,一直保持打开,直到调用了Reset方法。直到再次调用Set方法打开 大门。

六、使用CountDownEvent类

1. 使用CountDownEvent信号类来等待直到一定数量的操作完成。

2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics; namespace ThreadSynchronousDemo{    class Program    {        static CountdownEvent CountDownWork = new CountdownEvent(2);              static void Main(string[] args)        {            Console.WriteLine("开始,CountdownEvent 同步");                   var t = new Thread => working("第 1 个工作线程任务", 3)));            var t2 = new Thread => working("第 2 个工作线程任务", 6)));            //var t3 = new Thread => working("第 3 个工作线程任务", 12)));            t.Start();            t2.Start();            //t3.Start();            Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine("开始,线程工作计数");            CountDownWork.Wait();                       Console.WriteLine("计数完成,2个工作 已经完成!");            //如果把上面代码注释的第三个线程还原,释放对象,可以造成第三个线程的抛出错误            CountDownWork.Dispose();                 Console.Read();        }         static void working(string message,int seconds)        {            Console.WriteLine("工作前休息 {0}",DateTime.Now.Second);            Thread.Sleep(TimeSpan.FromSeconds;            Console.WriteLine;                      CountDownWork.Signal();            Console.WriteLine("发出计数信号, 工作已经完成一项");              }    }} 

3.程序运行结果如下图。

图片 3

程序启动时,创建了一个CountDownEven实例,在构造中指定了,当两个操作完成时给出信号。然后我们启动了两个线程进行工作,当第二个线程完成操作时,主线程从等待CountDownEvent的状态中返回并继续工作。这个类使用场景是,主线程需要等待多个线程完成工作之后,才能继续的情形。

缺点:必须要等待指定数量的线程全部完成工作,否则就一直会等待,请确保使用CountDownEvent时,所有线程完成工作后,都要调用Signal方法。

说明:

1) 把上面代码中注释的第三个线程的代码,还原则会出现以下错误。

图片 4

2) 如果把 第三个线程启用,同时把 CountDownWork.Dispose();注释,则会出现以下错误信息。

图片 5

二、问题

在使用swagger的过程中,产生了一些小问题,例如:汉化查询控制器备注
在博客园当中找到了相关的解决方式,但是汉化、控制器备注会产生二次请求的问题,尤其在接口比较多的情况下,还是比较慢的。因此产生了修改swagger-uiSwashbuckle源码的念头。

一、NSString的创建

写在前面的话

本文为Go官方网站 How to Write Go Code 这篇文章的翻译,
水平有限, 有些地方不好翻译的地方会用意译的方法, 关于代码示例的路径等方面可能也会有些不一样.

三、效果图

1.创建常量字符串:

介绍

本文演示如何开发一个简单的 go package, 以及 go tool 的使用方法,
即获取, 编译, 安装 go package 的标准方法和命令.

go tool 需要你安装一定的标准来组织代码. 请仔细阅读本文.
它介绍了用来构建和运行 Go 程序的最简单方法.

介绍本文的视频参照:

3.1 汉化效果

图片 6
图片 7

NSString *str1=@"Hello world! ";

代码组织

3.2 控制器注释以及接口数量统计

图片 8

2.先对字符串初始化,然后再赋值:

工作区

go tool 是设计用来和公共仓库的开源代码一起工作的.
即使你不需要发布你的代码, go tool 的工作模型也同样适用于你.

Go 代码必须保存在 工作区 中, 工作区 就是一个特定的目录结构, 根目录下有如下3个目录:

  • src 目录: 存放 go 源码文件, 按 package 来组织 (一个 package 一个文件夹)
  • pkg 目录: 存放 package 对象
  • bin 目录: 存放可执行文件

go tool 编译 src 下的文件, 并将编译好的二进制文件分别放入 pkg 或者 bin 文件夹中.
src 目录可以包含多个 VC 仓库(比如 Git 或 Mercurial), 用来管理代码的开发.

下面是一个目录结构的示例:

├── bin                                   # 这里存放 可执行命令├── pkg                                   # 这里存放 package 对象│   └── darwin_amd64│       ├── github.com│       └── go-files└── src    ├── github.com    │   └── golang    │       └── example    │           ├── .git    │           ├── hello               # 可执行命令的代码    │           ├── outyet              # 可执行命令的代码    │           └── stringutil          # package 代码    └── go-files        ├── .git        ├── hello                        # 可执行命令的代码        └── stringutil                   # package 代码

这里补充说明一下:
src 目录下:

  • github.com/golang/example 是 github 上的代码仓库
  • go-files 是本地的代码仓库

src 目录可以包含多个代码仓库, 可以包含多个命令的源码, 也可以包含多个 package 的源码.
大多数的 Go 程序员会将他们所有的 Go 源码和依赖关系保存在同一个工作区中.

可执行命令 和 库 是分别从不同的 package 的代码编译出来的, 稍后会讨论.

3.3 查询

图片 9

NSString *str2=[[NSString alloc]init];

GOPATH 环境变量

GOPATH 环境变量定义了你的 工作区 的位置. 这是你开发 Go 代码时唯一需要设置的环境变量.

开始开发时, 创建 工作区 的文件夹, 并设置对应的 GOPATH 环境变量.
你的 工作区 可以是任意文件夹, 本文中使用的路径是 $HOME/go
注意 不要把 GOPATH 设置为 go 的安装路径.

$ mkdir $HOME/go$ export GOPATH=$HOME/go

为了方便编译出的命令的执行, 将上面的 bin 目录加入到 PATH:

$ export PATH=$PATH:$GOPATH/bin

四、如何使用

str2=@"Hello world!!";

Package 路径

标准库中的 package 只要使用短路径即可, 比如 "fmt", "net/http".
对于自己的 package, 必须选一个基本的路径以防止以后和标准库, 或者其他第三方的库产生冲突.

如果你的代码保存在某个代码仓库, 那么就可以使用那个代码仓库的根目录作为你的 package 的基本路径.
比如, 你有个 github 的账户在 github.com/user, 就可以使用 github.com/user 作为你的基本路径.

注意 在能够正确编译代码之前, 你并不需要发布你的代码到远程的代码仓库.
但是如果有一天你会发布代码的话, 好好组织代码结构是个好习惯.
实际上, 你可以使用任意的路径名称, 只要它在 go 标准库和庞大的 go 生态系统中是唯一的.

我们使用 src/go-files 作为基本路径, 然后在工作区中创建文件夹来保存代码

$ mkdir -p $GOPATH/src/go-files

4.1 创建Webapi项目解决方案

3.带参数创建:

第一个 GO 程序

为了编译和运行一个简单的 GO 程序, 首先要确定 package 路径(这里使用 go-files/hello),
并且在工作区中创建对应 package 文件夹.

$ mkdir $GOPATH/src/go-files/hello

下一步, 在上面文件夹中创建 hello.go 文件, 文件内容如下:

package mainimport "fmt"func main() {    fmt.Printf("Hello, world.n")}

然后, 可以通过 go tool 来编译和安装上面的 hello 程序.

$ go install go-files/hello

你可以在任何路径下运行上述命令, go tool 会根据 GOPATH 环境变量来从工作区中查找 go-files/hello package.

如果在 package 所在文件夹中运行 go install, 也可以省略 package 路径.

$ cd $GOPATH/src/go-files/hello$ go install

上面的命令编译了 hello 命令, 并产生了此命令的二进制可执行文件.
然后将二进制文件 hello 安装到了 工作区 的 bin 文件夹下(Windows 下是 hello.exe)
在我们的例子中, 就是 $GOPATH/bin/hello, 即 $HOME/go/bin/hello

go tool 只有在出错时才会输出信息, 如果上面的 go 命令没有输出就说明执行成功了.
然后, 就可以在命令行中运行这个命令了.

$ $GOPATH/bin/hello

或者, 如果你将 $GOPATH/bin 加入到 PATH 中了的话, 也可以执行执行 hello 命令.

$ hello

如果你使用了代码版本管理工具, 这时就可以初始化你的仓库, 添加文件, 并 commit 你的第一个改变.
这个步骤是可选的, 写 go 代码并不强制要求使用代码版本管理工具.

$ cd $GOPATH/src/go-files/hello$ git init$ git add hello.go$ git commit -m "initial commit"

发布这个仓库, 使之成为读者的练习仓库.

4.2 引用SwashbuckleEx nuget包

SwashbuckleExSwashbuckleEx.Core这两个包
图片 10

NSString *str3=[[NSString alloc]initWithString:str1];

第一个 GO 库

让我们来写一个库, 并将之用于上面的 hello 程序中.
同样, 首先确定 package 路径 (这里使用 go-files/stringutil), 并创建对应的文件夹.

$ mkdir $GOPATH/src/go-files/stringutil

接着, 创建文件 reverse.go, 内容如下:

// Package stringutil contains utility functions for working with strings. package stringutil // Reverse returns its argument string reversed rune-wise left to right. func Reverse string {     r := []rune     for i, j := 0, len-1; i < len / 2; i, j = i 1, j-1 {         r[i], r[j] = r[j], r[i]     }     return string }

用 go build 来编译此 package

$ go build go-files/stringutil

或者在 package 的目录下, 直接运行 go build

$ cd $GOPATH/src/go-files/stringutil$ go build

上面的命令不会产生输出文件, 为了生成输出文件, 必须使用 go install 命令, 它会在 pkg 文件夹下生成 package 对象.
stringutil package 编译成功之后, 修改之前的 hello.go 文件:

package mainimport ( "fmt" "go-files/stringutil")func main() {     fmt.Printf(stringutil.Reverse("!oG ,olleH"))}

无论用 go tool 安装 package 对象还是 二进制文件, 它都会安装所有的依赖关系.
所以当你安装 hello 程序时,

$ go install go-files/hello

stringutil package 也会被自动安装.

运行新的 hello 程序, 可以看到如下输出:

$ helloHello, Go!

经过上面的步骤, 你的 工作区应该像下面这样:

bin/    hello                 # command executablepkg/    darwin_amd64/          # this will reflect your OS and architecture        go-files/            stringutil.a  # package objectsrc/    go-files/        hello/            hello.go      # command source        stringutil/            reverse.go    # package source

注意 go install 将 stringutil.a 放进了 pkg/darwin_amd64 文件夹下 和 代码对应的目录中.
以后, go tool 就可以找到这个 package, 从而判断是否需要重新编译.
darwin_amd64 是表示当前使用的系统, 它的目的是为了区分交叉编译出的其他平台的 package.

Go 编译出的二进制文件都是静态链接的, 所以上面的 bin/hello 在执行时并不需要 darwin_amd64/go-files/stringutil.a 文件.

4.3 添加接口注释

完成上面2部运行项目,可以看到接口描述已经生成,浏览地址http://xxxx/swagger。但是没有接口的注释,下面添加接口注释。

NSString *str4=[[NSString alloc]initWithFormat:@"%@",str1];

Package name

go 代码的第一行必须是:

package name

这里的 name 作为 package 的默认名称, 让其他 package import 的时候用.(同个 package 中的所有文件必须使用相同的 name)
Go 的习惯是: package name 是 import path 中最后一部分.
也就是说, 如果一个 package 被引用时写成 "crypto/rot13", 那么这个 package 的 name 就是 rot13

编译为可执行文件的代码的 package name 必须是 main
一个二进制文件所关联的多个 package 的 name 不一定要唯一, 只要 pakage 的 import path 是唯一的就行.
也就是上面的 crypto/rot13 必须唯一, 但是可以有 another-crypto/rot13.

Go 的命名规则可以参考:

4.3.1 项目属性->勾选生成xml文档文件

注:如果实体与Api库分开,那么需要在实体库也勾选上生成xml文件,并设置文件名称。

图片 11

NSString *str5=[[NSString alloc]initWithString:[NSString stringWithFormat:@"%@",str1 ]];

测试

Go 中包含一个轻量级的测试框架, 由 go test 命令和 testing package 组成.

测试文件的名称以 _test.go 结尾, 其中包含格式如 func TestXXXX(t *testing.T) 的函数.
测试框架会执行每个这样的函数, 如果函数中调用了 t.Error 或者 t.Fail, 就认为测试失败.

给上面的 package stringutil 增加测试文件, 路径: $GOPATH/src/go-files/stringutil/reverse_test.go, 内容如下:

package stringutilimport "testing"func TestReverse(t *testing.T) {  cases := []struct {      in, want string  }{      {"Hello, world", "dlrow ,olleH"},      {"Hello, 世界", "界世 ,olleH"},      {"", ""},  }  for _, c := range cases {      got := Reverse      if got != c.want {          t.Errorf("Reverse == %q, want %q", c.in, got, c.want)      }  }}

执行测试的方法如下:

$ go test go-files/stringutil

或者进入到 package stringutil 的目录中后, 直接运行:

$ go test

通过 go help test 或者 来进一步 GO 的测试框架.

4.3.2 修改SwaggerConfig.cs文件

c.SingleApiVersion("v1", "xxx");c.IncludeXmlComments(string.Format("{0}/bin/xxx.Api.XML", AppDomain.CurrentDomain.BaseDirectory));

图片 12
给接口添加注释,即可看到参数与方法描述了。

二、字符串的比较

远程 package

Go 的 import path 可以描述如何从版本管理系统(Git 或者 Mercurial) 中获取 package 的源码.
go tool 可以利用这个特性来自动获取远程仓库的代码.
比如, 下面的例子中使用的代码同时也保存在 github 上().

如果你在代码中 import 了上面这个远程的 package, 那么 go get 命令会自动 获取, 编译, 安装这个 package.

$ go get github.com/golang/example/hello$ helloHello, Go examples!

如果本地没有指定 import 的 package, go get 命令会把这个 package 下载到 GOPATH 中定义的第一个工作区中.
(如果远程 package 不存在的话, go get 相当于 go install)

上面的 go get 命令执行之后, 文件夹结构大致如下:

├── bin│   └── hello├── pkg│   └── darwin_amd64│       ├── github.com│       │   └── golang│       │       └── example│       │           └── stringutil.a│       └── go-files└── src    ├── github.com    │   └── golang    │       └── example    │           ├── .git    │           ├── hello    │           │   └── hello.go    │           └── stringutil    │               ├── reverse.go    │               └── reverse_test.go    └── go-files        ├── hello        │   └── hello.go        └── stringutil            ├── reverse.go            └── reverse_test.go

github.com 上的 hello 程序依赖同一个仓库中的 package stringutil,
即 github.com 上的 hello.go 中引用了 github.com 上的 package stringutil, 所以, go get 命令也下载, 编译, 安装了 stringutil 模块.

import (  "fmt"  "github.com/golang/example/stringutil")

这个特性可以让你的 go package 很容易的被别人使用.
Go Wiki 和 godoc.org 上列出了很多第三方 Go 工程.
关于使用 go tool 来使用远程仓库的更多信息, 请参考: go help importpath

4.3.3 配置Web.config文件

有园友提出使用Nuget包后,展示是空的,因此看了下,需要配置一下以下的内容即可。

<system.webServer>    <modules runAllManagedModulesForAllRequests="true">        <remove name="WebDAVModule" />    </modules></system.webServer>

图片 13

1.isEqualToString方法:用来判断两个字符串是否相等:

下一步

  • 订阅 golang-announce 邮件列表来了解最新的 Go release 信息
  • 将 Effective Go 作为参考资料来编写整洁, 地道的 Go 代码
  • 通过 A Tour of Go 来完成一次 go 的旅行
  • 访问 documentation page 来了解一系列关于Go语言的有深度的文章, 以及 Go 库和工具.

五、源码地址

Github:

if([str1 isEqualToString:str2]){

获取帮助

  • 寻求实时帮助, 可以使用 FreeNode 的IRC server #go-nuts
  • Go 语言官方邮件列表 Go Nuts
  • 汇报 Go 语言的 bug 请使用 Go issue tracker

本文由小鱼儿玄机30码发布于编程,转载请注明出处:接下来再赋值,有个别地点不佳翻译的地点会用

关键词: 小鱼儿玄机30码