Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add:3&&4周作业 #16

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions homework/caojiangjiang/week3/leetcode/leetCode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package leetcode
//
// 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/container-with-most-water
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
//
func maxArea(height []int) int {
value := 0
max := 0
left := 0
right := len(height) - 1
for {
if (left >= right) {
return max;
}
if (height[left] > height[right]) {
value = (right - left) * height[right]
right = right - 1
} else {
value = (right - left) * height[left]
left = left + 1
}
if (value > max) {
max = value
}
}
}
52 changes: 52 additions & 0 deletions homework/caojiangjiang/week3/practice/question1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"log"
"os"
"strings"
"time"
)

func sayhello(w http.ResponseWriter, r *http.Request) {
go writeLog(w, r);
fmt.Fprintf(w, "Hello world!") // 这个写入到 w 的是输出到客户端的
}

/**
* 方法功能:监听端口,异步写入日志
*/
func main() {
http.HandleFunc("/", sayhello) // 设置访问的路由
err := http.ListenAndServe(":9090", nil) // 设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

func writeLog(w http.ResponseWriter, r *http.Request) {
url := r.URL.Path
query := r.URL.RawQuery
method := r.Method
methodInfoMap := map[string] interface{}{
"url" : url,
"method" : method,
"query" : query,
"response": "hello world!",
}
methodInfoJson, _ := json.Marshal(methodInfoMap)
methodInfoStr := string(methodInfoJson)
fileName := "/tmp/homework.log" // 根目录下的tmp目录下
_, err := os.Stat(fileName)
if err != nil || os.IsNotExist(err) {
os.Create(fileName)
}
fd,_:=os.OpenFile(fileName,os.O_RDWR|os.O_CREATE|os.O_APPEND,0666)
defer fd.Close()
fd_time:=time.Now().Format("2006-01-02 15:04:05");
fd_content:=strings.Join([]string{"======",fd_time,"=====",methodInfoStr,"\n"},"")
buf:=[]byte(fd_content)
fd.Write(buf)
}
135 changes: 135 additions & 0 deletions homework/caojiangjiang/week3/practice/question2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package main

/**
* 方法功能:平滑重启
*/
import (
"context"
"errors"
"flag"
"log"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"syscall"
"time"
)

var (
server *http.Server
listener net.Listener
// 在 go 标准库中提供了一个包:flag,方便进行命令行解析
// flag.Xxx(),其中 Xxx 可以是 Int、String,Bool 等;返回一个相应类型的指针
graceful = flag.Bool("graceful", false, "listen on fd open 3 (internal use only)")
)

func sleep(w http.ResponseWriter, r *http.Request) {
// 请输入(x)s,比如:10s,不要忘记加s
duration, err := time.ParseDuration(r.FormValue("duration"))
if err != nil {
http.Error(w, err.Error(), 400)
return
}
time.Sleep(duration)
w.Write([]byte("Hello World"))
}


// 父进程监听重启信号
// 在收到重启信号后,父进程调用 fork ,同时传递 socket 描述符给子进程
// 子进程接收并监听父进程传递的 socket 描述符
// 在子进程启动成功之后,父进程停止接收新连接,同时等待旧连接处理完成(或超时)
// 父进程退出,热重启完成

// 执行步骤:
// 1. 启动这个程序(你要是不知道咋启动,劝你还是别看这代码了,看了你也看不懂,懂了你也不会用)
// 2. 浏览器运行localhost:5007/sleep
// 3. 打开iterm 输入 kill -USR2 进程号(用ps -ef|grep question就可以搜到了)
// 4. 观察输出
func main() {
// 解析命令行参数到定义的flag
flag.Parse()

http.HandleFunc("/sleep", sleep)
server = &http.Server{Addr: ":5007"}

var err error
if *graceful {
log.Print("main: Listening to existing file descriptor 3.")
// cmd.ExtraFiles: If non-nil, entry i becomes file descriptor 3+i.
// when we put socket FD at the first entry, it will always be 3(0+3)
// 子进程的 0, 1, 2 是预留给标准输入、标准输出、错误输出,故传递的 socket 描述符应放在子进程的 3
f := os.NewFile(3, "")
listener, err = net.FileListener(f)
} else {
log.Print("main: Listening on a new file descriptor.")
listener, err = net.Listen("tcp", server.Addr)
}

if err != nil {
log.Fatalf("listener error: %v", err)
}

go func() {
// server.Shutdown() stops Serve() immediately, thus server.Serve() should not be in main goroutine
err = server.Serve(listener)
log.Printf("server.Serve err: %v\n", err)
}()
signalHandler()
log.Printf("signal end")
}

func reload() error {
tl, ok := listener.(*net.TCPListener)
if !ok {
return errors.New("listener is not tcp listener")
}

f, err := tl.File()
if err != nil {
return err
}
// 设置传递给子进程的参数(包含 socket 描述符)
args := []string{"-graceful=true"}
cmd := exec.Command(os.Args[0], args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// put socket FD at the first entry
cmd.ExtraFiles = []*os.File{f}
log.Println(cmd)
return cmd.Start()
}

func signalHandler() {
ch := make(chan os.Signal, 1)
// 注册一个os.Signal以监听
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR2)
for {
sig := <-ch
log.Printf("signal: %v", sig)

// timeout context for shutdown
ctx, _ := context.WithTimeout(context.Background(), 100*time.Second)
switch sig {
case syscall.SIGINT, syscall.SIGTERM:
// stop
log.Printf("stop")
signal.Stop(ch)
server.Shutdown(ctx)
log.Printf("graceful shutdown")
return
case syscall.SIGUSR2:
// reload
log.Printf("reload")
err := reload()
if err != nil {
log.Fatalf("graceful restart error: %v", err)
}
server.Shutdown(ctx)
log.Printf("graceful reload")
return
}
}
}
36 changes: 36 additions & 0 deletions homework/caojiangjiang/week3/theory/theory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
go语言中init函数用于包(package)的初始化,该函数是go语言的一个重要特性。

有下面的特征:

1 init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等

2 每个包可以拥有多个init函数

3 包的每个源文件也可以拥有多个init函数

4 同一个包中多个init函数的执行顺序go语言没有明确的定义(说明)

5 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序

6 init函数不能被其他函数调用,而是在main函数执行之前,自动被调用
main函数

Go语言程序的默认入口函数(主函数):func main()
函数体用{}一对括号包裹。

func main(){
//函数体
}
init函数和main函数的异同

相同点:
两个函数在定义时不能有任何的参数和返回值,且Go程序自动调用。
不同点:
init可以应用于任意包中,且可以重复定义多个。
main函数只能用于main包中,且只能定义一个。
两个函数的执行顺序:
对同一个go文件的init()调用顺序是从上到下的。
对同一个package中不同文件是按文件名字符串比较“从小到大”顺序调用各文件中的init()函数。
对于不同的package,如果不相互依赖的话,按照main包中"先import的后调用"的顺序调用其包中的init(),如果package存在依赖,则先调用最早被依赖的package中的init(),最后调用main函数。

如果init函数中使用了println()或者print()你会发现在执行过程中这两个不会按照你想象中的顺序执行。这两个函数官方只推荐在测试环境中使用,对于正式环境不要使用。
49 changes: 49 additions & 0 deletions homework/caojiangjiang/week4/letCode/leetcode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import "fmt"

//
// 在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。
// 由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。
// 开始坐标总是小于结束坐标。平面内最多存在104个气球。
//
// 一支弓箭可以沿着x轴从不同点完全垂直地射出。
// 在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。
// 可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。
//
//来源:力扣(LeetCode)
//链接:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons
//著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
//
// 思路:根据最小的进行排序
//
func main() {
points := [][]int{{3,9}, {7,12}, {3,8}, {6,8}, {9,10}, {2, 9}, {0, 9}, {3, 9}, {0, 6}, {2, 8}}
result := findMinArrowShots(points)
fmt.Println(result)
}

func findMinArrowShots(points [][]int) int {
if (len(points) == 0) {
return 0
}
for i := 0; i < len(points); i++ {
for j := 0; j < len(points) - 1 - i; j ++ {
if points[j][1] > points[j + 1][1] {
tmp := points[j]
points[j] = points[j + 1]
points[j + 1] = tmp
}
}
}
min := points[0][1]
result := 1
for i := 1; i < len(points); i++ {
if points[i][0] <= min {
continue
}
result += 1
min = points[i][1]
}
return result
}
Loading