Python Flask快速入门与进阶

449 阅读1分钟

download:Python Flask快速入门与进阶

掌握了Python基础语法的同学,都知道下一步要学习Python框架了,但选什么框架,如何快速的渡过这个“卡顿”期,一直是个“老大难”问题。我们建议小白可以通过Flask来过渡与入门,FLask 本身“轻”的特点,让你的学习不会那么“重”,掌握核心知识就能进行开发 ,更容易获得成就感,学习也就会更有动力,另外,FLask虽轻,但Flask 很强,内核+扩展的特点,让FLask 拥有“快速”开发各种类型应用的能力,在Python Web领域也是非常受市场认可的

适合人群
掌握Python基础语法却不知下一步学习方向的同学
刚刚接触Python Web开发的同学

技术储备要求
掌握Python基础语法
了解MySQL 基础知识
(掌握基础的增删改查)

// Acquire acquires the semaphore with a weight of n, blocking until resources // are available or ctx is done. On success, returns nil. On failure, returns // ctx.Err() and leaves the semaphore unchanged. // // If ctx is already done, Acquire may still succeed without blocking. func (s *Weighted) Acquire(ctx context.Context, n int64) error { // 有可用資源,直接勝利返回nil s.mu.Lock() if s.size-s.cur >= n && s.waiters.Len() == 0 { s.cur += n s.mu.Unlock() return nil } // 懇求資源權重遠遠超出了設置的最大權重和,失敗返回 ctx.Err() if n > s.size { // Don't make other Acquire calls block on one that's doomed to fail. s.mu.Unlock() <-ctx.Done() return ctx.Err() } // 有局部資源可用,將懇求者放在等候隊列(頭部),並經過select 完成通知其它waiters ready := make(chan struct{}) w := waiter{n: n, ready: ready} // 放入链表尾部,並返回放入的元素 elem := s.waiters.PushBack(w) s.mu.Unlock() select { case <-ctx.Done(): // 收到外面的控製信號 err := ctx.Err() s.mu.Lock() select { case <-ready: // Acquired the semaphore after we were canceled. Rather than trying to // fix up the queue, just pretend we didn't notice the cancelation. // 假如在用戶取消之前曾經獲取了資源,則直接疏忽這個信號,返回nil表示勝利 err = nil default: // 收到控製信息,且還沒有獲取到資源,就直接將原來添加的 waiter 删除 isFront := s.waiters.Front() == elem // 則將其從链接删除 上面 ctx.Done() s.waiters.Remove(elem) // 假如當前元素正好位於链表最前面,且還存在可用的資源,就通知其它waiters if isFront && s.size > s.cur { s.notifyWaiters() } } s.mu.Unlock() return err case <-ready: return nil } }
留意上面在select逻輯语句上面有一次加解鎖的操作,在 select 里面由於是全局鎖所以還需求再次加鎖。

依據可用計數器信息,可分三種狀況:

關於 TryAcquire() 就比擬简單了,就是一個可用資源數量的判別,數量夠用表示勝利返回 true ,否則 false,此辦法並不會停止阻塞,而是直接返回。
// TryAcquire acquires the semaphore with a weight of n without blocking.
// On success, returns true. On failure, returns false and leaves the semaphore unchanged.
func (s *Weighted) TryAcquire(n int64) bool {
s.mu.Lock()
success := s.size-s.cur >= n && s.waiters.Len() == 0
if success {
s.cur += n
}
s.mu.Unlock()
return success
}
释放 Release

關於释放也很简單,就是將已運用資源數量(計數器)停止更新減少,並通知其它 waiters。

// Release releases the semaphore with a weight of n.
func (s *Weighted) Release(n int64) {
s.mu.Lock()
s.cur -= n
if s.cur < 0 {
s.mu.Unlock()
panic("semaphore: released more than held")
}
s.notifyWaiters()
s.mu.Unlock()
}
通知機製

經過 for 循環從链表頭部開端頭部依次遍歷出链表中的一切waiter,並更新計數器 Weighted.cur,同時將其從链表中删除,直到遇到 閑暇資源數量 < watier.n 爲止。

func (s *Weighted) notifyWaiters() {
for {
next := s.waiters.Front()
if next == nil {
break // No more waiters blocked.
}
w := next.Value.(waiter)
if s.size-s.cur < w.n {
// Not enough tokens for the next waiter. We could keep going (to try to
// find a waiter with a smaller request), but under load that could cause
// starvation for large requests; instead, we leave all remaining waiters
// blocked.
//
// Consider a semaphore used as a read-write lock, with N tokens, N
// readers, and one writer. Each reader can Acquire(1) to obtain a read
// lock. The writer can Acquire(N) to obtain a write lock, excluding all
// of the readers. If we allow the readers to jump ahead in the queue,
// the writer will starve — there is always one token available for every
// reader.
break
}
s.cur += w.n
s.waiters.Remove(next)
close(w.ready)
}
}
能夠看到假如一個链表里有多個等候者,其中一個等候者需求的資源(權重)比擬多的時分,當前 watier 會呈現長時間的阻塞(即便當前可用資源足夠其它waiter執行,期間會有一些資源糜费), 直到有足夠的資源能夠讓這個等候者執行,然後繼續執行它後面的等候者。

運用示例

官方文檔提供了一個基於信號量的典型的“工作池”形式,見pkg.go.dev/golang.org/… goroutine 並發工作。

這是一個經過信號量完成並發對 考拉兹猜測的示例,對1-32之間的數字停止計算,並打印32個契合結果的值。

package main
import (
"context"
"fmt"
"log"
"runtime"
"golang.org/x/sync/semaphore"
)
// Example_workerPool demonstrates how to use a semaphore to limit the number of
// goroutines working on parallel tasks.
//
// This use of a semaphore mimics a typical “worker pool” pattern, but without
// the need to explicitly shut down idle workers when the work is done.
func main() {
ctx := context.TODO()
// 權重值爲逻輯cpu個數
var (
maxWorkers = runtime.GOMAXPROCS(0)
sem = semaphore.NewWeighted(int64(maxWorkers))
out = make([]int, 32)
)
// Compute the output using up to maxWorkers goroutines at a time.
for i := range out {
// When maxWorkers goroutines are in flight, Acquire blocks until one of the
// workers finishes.
if err := sem.Acquire(ctx, 1); err != nil {
log.Printf("Failed to acquire semaphore: %v", err)
break
}
go func(i int) {
defer sem.Release(1)
out[i] = collatzSteps(i + 1)
}(i)
}
// 假如運用了 errgroup 原语則不需求下面這段语句
if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil {
log.Printf("Failed to acquire semaphore: %v", err)
}
fmt.Println(out)
}
// collatzSteps computes the number of steps to reach 1 under the Collatz
// conjecture. (See en.wikipedia.org/wiki/Collat….)
func collatzSteps(n int) (steps int) {
if n <= 0 {
panic("nonpositive input")
}
for ; n > 1; steps++ {
if steps < 0 {
panic("too many