线程(下)

线程的定义

线程是操作系统能够进行演算调整的纤维单位。它被含有在进度中。是进程中的实际运营单位。一条线程指的是经过中3个单纯顺序的调整流。3个经过中能够并发四个线程,每条线程并行实施差别的天职
多个线程的实行会因此线程的调整去抢占CPU的资源

线程与经过

1、同步锁 (Lock)

  当全局能源(counter)被并吞的情形,难点时有发生的由来尽管从未决定八个线程对同1财富的访问,对数据造成破坏,使得线程运转的结果不可预料。那种现象叫做“线程不安全”。在开采进度中大家亟须求制止这种处境,这怎么制止?那就用到了互斥锁了。

例如:

 1 import threading,time
 2 def sub():
 3     global num         #对全局变量进行操作
 4 
 5     temp=num
 6     time.sleep(0.001)    #模拟线程执行中出现I/o延迟等
 7     num=temp-1           #所有线程对全局变量进行减一
 8 
 9     time.sleep(1)
10 
11 num=100
12 l=[]
13 
14 for i in range(100):
15     t=threading.Thread(target=sub,args=())
16     t.start()
17     l.append(t)
18 
19 for obj in l:
20     obj.join()
21 
22 print(num)          
23 
24 #执行结果不可预期:
25 >>:90
26 >>:93
27 >>:92
28 

7.同步锁

其壹例子很特出,实话说,那个事例笔者是直接照搬前辈的,并不是原创,可是真的也很有趣,请看:

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva

import threading,time

number = 100
def subnum():
    global number
    number -= 1

threads = []
for i in range(100):
    t = threading.Thread(target=subnum,args=[])
    t.start()
    threads.append(t)

for i in threads:
    i.join()

print(number)

 

这段代码的意思是,用九十八个线程去减一,以此让变量number为十0的变为0

 

结果:

 

金沙注册送58 1

 

那么自身有点的改下代码看看: 

 

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva

import threading,time

number = 100
def subnum():
    global number
    temp = number
    time.sleep(0.2)
    number = temp -1

threads = []
for i in range(100):
    t = threading.Thread(target=subnum,args=[])
    t.start()
    threads.append(t)

for i in threads:
    i.join()

print(number)

  

并从未非常大的更换对吗,只是加了多个一时变量,并且中途抛锚了0.2s而已。

而以此结果就差别等了:

金沙注册送58 2

 

那边本人先说下,time.sleep(0.二)是自家故意加的,正是要突显那么些职能,借使你的微管理器不加sleep就早已面世那个场地了那么你就不用加了,那咋回事呢?那便是线程共用多少的机密危急性,因为线程都以抢着CPU能源在运作,只要发觉有空儿就各自抢着跑,所以在那停顿的0.2s时间中,就会有新的线程抢到机会开首运营,那么九十七个线程就有9二十一个线程在抢机会运营,抢到的时间都以在temp还不曾减一的值,相当于拾0,所以大多数的线程都抢到了100,然后减一,少一些线程没抢到,抢到已经减了三次的9九,那就是怎么会是9玖的原由。而那个抢占的光阴和结果并不是一直的缘由,究其根本依然因为Computer的布署难点了,配置越好的话,那种越不轻易爆发,因为一个线程抢到CPU财富后直接在运作,别的的线程在短短的岁月里得不到机会。

_进程与线程中的lock,洗礼灵魂。 

而为啥number -= 1,不借助于任何变量的写法就没事吧?因为numebr -=
一事实上是八个步骤,减一并再一次赋值给number,那么些动作太快,所以根本没给别的的线程机会。

 

图解: 

金沙注册送58 3

 

那就是说这些标题我们怎么化解吧,在后来的付出中绝对会遇上那种场合对吗,那个能够消除呢?根据上边的教授,有人会想到用join,而日前早已提过了join会使多线程变成串行,失去了102线程的意图。那个到底怎么消除呢,用同步锁

同步锁:当运维起来加锁,幸免别的线程索取,当运转甘休释放锁,让其它线程继续

 

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
import threading,time

r = threading.Lock() #创建同步锁对象

number = 100
def subnum():
    global number
    r.acquire() #加锁
    temp = number
    time.sleep(0.2)
    number = temp - 1
    r.release() #释放


threads = []
for i in range(100):
    t = threading.Thread(target=subnum,args=[])
    t.start()
    threads.append(t)

for i in threads:
    i.join()

print(number)

  

运作结果:

金沙注册送58 4

 

可是你意识没,那么些运营太慢了,每一个线程都运营了三回sleep,竟然又产生和串行运营大概了对吧?不过照旧和串行稍微有点分化,只是在有三只锁那里是串行,在任啥地方方大概十二线程的功用

 

那正是说有意中人要问了,既然都以锁,已经有了贰个GIL,那么还要同步锁来干嘛呢?一句话,GIL是注重于保证线程安全,同步锁是用户级的可控机制,开荒中幸免那种不明确的神秘隐患

 

进程的概念

程序试行的实例称为进度
各类进度提供施行顺序所需的财富。进度具备虚拟地址空间,可施行代码,系统对象的开垦句柄,安全上下文,唯壹进度标记符,情状变量,优先级等级次序,最小和最大职业集。每一个进程都使用单线程运维,常常称为主线程,但能够从其任何线程创立其它线程

进程和线程的相比较
进程和线程之间的相比是不曾意义的,因为经过是二个主次的进行实例,而经过是由线程举办实行的,但线程和进度毕竟依然三种机制

  • 进程能够创设子进度,而各种子进度又有什么不可开四个线程
  • 线程之间能够共享数据,而线程之间无法共享数据,线程之间能够开始展览通讯,而经过之间开始展览通讯就会比较费心
  • 开荒进度要比开垦线程的开支大过多

什么是线程(thread)?

线程是操作系统能够进行演算调整的小小单位。它被含有在进程之中,是经过中的实际运作单位。一条线程指的是进程中一个单纯顺序的调整流,二个历程中得以并发四个线程,每条线程并行试行不相同的天职

A thread is an execution context, which is all the information a CPU
needs to execute a stream of instructions.

Suppose you’re reading a book, and you want to take a break right now,
but you want to be able to come back and resume reading from the exact
point where you stopped. One way to achieve that is by jotting down the
page number, line number, and word number. So your execution context for
reading a book is these 3 numbers.

If you have a roommate, and she’s using the same technique, she can take
the book while you’re not using it, and resume reading from where she
stopped. Then you can take it back, and resume it from where you were.

Threads work in the same way. A CPU is giving you the illusion that it’s
doing multiple computations at the same time. It does that by spending a
bit of time on each computation. It can do that because it has an
execution context for each computation. Just like you can share a book
with your friend, many tasks can share a CPU.

On a more technical level, an execution context (therefore a thread)
consists of the values of the CPU’s registers.

Last: threads are different from processes. A thread is a context of
execution, while a process is a bunch of resources associated with a
computation. A process can have one or many threads.

Clarification: the resources associated with a process include memory
pages (all the threads in a process have the same view of the memory),
file descriptors (e.g., open sockets), and security credentials (e.g.,
the ID of the user who started the process).

互斥锁概念

  Python编制程序中,引进了目的互斥锁的概念,来担保加利亚共产党享数据操作的完整性。每种对象都对应于3个可称为”
互斥锁”
的符号,这一个标识用来保障在任一时半刻刻,只可以有二个线程访问该目的。在Python中大家选取threading模块提供的Lock类。

  大家对地方的顺序开展整顿,为此我们须要加上三个排斥锁变量lock =
threading.Lock(),然后在勇斗能源的时候后边我们会先抢占那把锁lock.acquire(),对财富使用完了之后大家在假释那把锁mutex.release()。

代码如下:

import threading,time
def sub():
    global num

    lock.acquire()
    temp=num
    time.sleep(0.01)
    num=temp-1
    lock.release()

    time.sleep(1)

num=100
l=[]
lock=threading.Lock()
for i in range(100):
    t=threading.Thread(target=sub,args=())
    t.start()
    l.append(t)

for obj in l:
    obj.join()

print(num)

 8.死锁现象/可选拔锁

前方既然已经用了伙同锁,那么相信在事后的开销中,绝对会用到应用几个同步锁的时候,所以这边模拟一下用到多少个共同锁,看看会有啥样境况爆发

 

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
import threading,time

a = threading.Lock() #创建同步锁对象a
b = threading.Lock() #创建同步锁对象b

def demo1():
    a.acquire() #加锁
    print('threading model test A....')
    b.acquire()
    time.sleep(0.2)
    print('threading model test B....')
    b.release()
    a.release() #释放

def demo2():
    b.acquire() #加锁
    print('threading model test B....')
    a.acquire()
    time.sleep(0.2)
    print('threading model test A....')
    a.release()
    b.release() #释放

threads = []
for i in range(5):
    t1 = threading.Thread(target=demo1,args=[])
    t2 = threading.Thread(target=demo2,args=[])
    t1.start()
    t2.start()
    threads.append(t1)
    threads.append(t2)

for i in threads:
    i.join()

 

  

运维结果:

金沙注册送58 5

 

那边就径直阻塞住了,因为demo一函数用的锁是外围a锁,内层b锁,demo2函数刚好相反,外层b锁,内层a锁,所以当10贰线程运维时,七个函数同时在互抢锁,哪个人也不让哪个人,这就招致了绿灯,这些阻塞现象又叫死锁现象。

 

那就是说为了制止生出那种事,大家得以运用threading模块下的酷路泽LOCK来创建重用锁依此来制止那种情景

 

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
import threading,time

r = threading.RLock() #创建重用锁对象

def demo1():
    r.acquire() #加锁
    print('threading model test A....')
    r.acquire()
    time.sleep(0.2)
    print('threading model test B....')
    r.release()
    r.release() #释放

def demo2():
    r.acquire() #加锁
    print('threading model test B....')
    r.acquire()
    time.sleep(0.2)
    print('threading model test A....')
    r.release()
    r.release() #释放

threads = []
for i in range(5):
    t1 = threading.Thread(target=demo1,args=[])
    t2 = threading.Thread(target=demo2,args=[])
    t1.start()
    t2.start()
    threads.append(t1)
    threads.append(t2)

for i in threads:
    i.join()

  

运转结果:

金沙注册送58 6

 

本条奥迪Q五lock其实正是Lock+总计器,总结器里的初阶值为0,每嵌套一层锁,总括器值加一,每释放一层锁,计算器值减一,和一块锁同样,唯有当班值日为0时才算了却,让任何线程接着抢着运转。而以此库罗德lock也有一个法定一点的名字,递归锁

 

 那么估算有朋友会问了,为何会有死锁现象吧?也许您应当问,是何许生产景况导致有死锁现象的,依然那句,为了掩护数量同步性,防止10贰线程操作同壹数据时爆发争执。那么些说辞很暧昧对吧,小编说细点。比方前面包车型大巴购物车系统,即便大家在操作数据时又再一次取了2遍数据来有限支撑数据的真实,假诺多个用户同时登陆购物车系统在操作的话,也许差异的操作但会提到到同三个数量的时候,就会导致数据大概不联合了,那么就足以在中间代码里加一遍联合锁,然后再在实际上操作处再加一遍联袂锁,那样就出现多层同步锁,那么也就会产出死锁现象了,而那时候以此死锁现象是我们开辟中正好供给的。

自己想,说了那个事例你应该能够明白为啥lock里还要有lock,很轻巧产生死锁现象大家照旧要用它了,一句话来说若是急需死锁现象就用1道锁,不要求就换到递归锁。

 

Python中开创线程

Python中开创线程有多样情势

如何是进程(process)?

An executing instance of a program is called a process.

Each process provides the resources needed to execute a program. A
process has a virtual address space, executable code, open handles to
system objects, a security context, a unique process identifier,
environment variables, a priority class, minimum and maximum working set
sizes, and at least one thread of execution. Each process is started
with a single thread, often called the primary thread, but can create
additional threads from any of its threads.

二、死锁与递归锁

  所谓死锁:
是指八个或四个以上的历程或线程在实施进程中,因争夺财富而导致的一种互动等待的景色,若无外力成效,它们都将相当的小概推进下去。此时称系统处于死锁状态或连串发出了死锁,这一个长久在竞相等待的历程称为死锁进程。 

会产生死锁的事例:

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        self.foo()


    def foo(self):
        LockA.acquire()
        print('I am %s GET LOCKA---------%s'%(self.name,time.ctime()))
        LockB.acquire()
        print('I am %s GET LOCKB---------%s' % (self.name, time.ctime()))

        LockB.release()

        LockA.release()

LockA=threading.Lock()
LockB=threading.Lock()

for i in range(10):
    t=MyThread()
    t.start()

 九.实信号量/绑定式非功率信号量

时域信号量也是八个线程锁

1)Semaphore

信号量以为更有具备二十多线程的意义。先不急着说,看看例子就懂:

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
import threading,time

s = threading.Semaphore(3) #创建值为3的信号量对象

def demo():
    s.acquire() #加锁
    print('threading model test A....')
    time.sleep(2)
    s.release() #释放

threads = []
for i in range(10):
    t = threading.Thread(target=demo,args=[])
    t.start()
    threads.append(t)

for i in threads:
    i.join()

  

运行结果:

金沙注册送58 7

 

若果你亲自测试那段代码,你会意识,这几个结果是二个一组出的,出了2次三个一组的,最终出了一个壹组,三个一组都是相互的,中间停顿2秒。

那边能够给很形象的事例,假若有个别地方的停车位只可以同时停三辆车,当停车位有空时别的的车才足以停进来。那里的一个停车位就一定于复信号量。

 

2)BoundedSemaphore

既是有复信号量为大家做到那几个一组壹组的操作结果,但敢不敢保险那几个线程就不会突然的越出这一个设定好的车位呢?比方设定好的3个随机信号量一组,大家都清楚线程是争强着运转,万一就有除了设定的2个线程外的一五个线程抢到了运行权,什么人也不让何人,正是要共同运行吧?好比,那里唯有1个车位,已经停满了,但有人就是要去挤壹挤,出现第陆辆也许第伍辆车的场地,这几个和现实生活中的例子大约太合适了对啊?

那正是说大家如何是好?当然那些难点早就有人想好了,所以有了复信号量的升官版——绑定式功率信号量(Bounded塞马phore)金沙注册送58 ,。既然是提拔版,那么同非非确定性信号量同样该部分都有的,用法也一律,正是有个职能,在设定好的多少个线程1组运营时,假若有其余线程也抢到运转权,那么就会报错

比如thread_lock =
threading.BoundedSemaphore(五),那么四线程同时运维的线程数就务须在伍以内(包蕴伍),不然就报错。换句话,它装有了实时监督检查的功能,好比停车位上的保险,借使开掘车位满了,就不准放行车辆,直到有空位了再允许车辆进入停车。

因为那么些很简短,就多了个督察成效,别的和semaphore同样的用法,笔者就不演示了,自身雕刻吧

 

threading 模块

经过与线程的不一样?

  1. Threads share the address space of the process that created it;
    processes have their own address space.
  2. Threads have direct access to the data segment of its process;
    processes have their own copy of the data segment of the parent
    process.
  3. Threads can directly communicate with other threads of its process;
    processes must use interprocess communication to communicate with
    sibling processes.
  4. New threads are easily created; new processes require duplication of
    the parent process.
  5. Threads can exercise considerable control over threads of the same
    process; processes can only exercise control over child processes.
  6. Changes to the main thread (cancellation, priority change, etc.) may
    affect the behavior of the other threads of the process; changes to
    the parent process does not affect child processes.

利用递归锁消除:

  在Python中为了援助在同壹线程中反复呼吁同1能源,python提供了可重入锁途胜Lock。那么些宝马X3Lock内部维护着3个Lock和二个counter变量,counter记录了acquire的次数,从而使得能源能够被频仍require。直到一个线程全部的acquire都被release,别的的线程才干赢得能源。上边的例证即便选拔本田CR-VLock替代Lock,则不会发生死锁:

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        self.foo()
        self.bar()

    def foo(self):
        RLock.acquire()
        print('I am %s GET LOCKA---------%s'%(self.name,time.ctime()))
        RLock.acquire()
        print('I am %s GET LOCKB---------%s' % (self.name, time.ctime()))

        RLock.release()
        RLock.release()

    def bar(self):

        RLock.acquire()
        print('I am %s GET LOCKB---------%s' % (self.name, time.ctime()))
        time.sleep(1)
        RLock.acquire()
        print('I am %s GET LOCKA---------%s' % (self.name, time.ctime()))

        RLock.release()
        RLock.release()

RLock=threading.RLock()

for i in range(10):
    t=MyThread()
    t.start()

  

拾.规范变量同步锁

不多说,它也是二个线程锁,本质上是在猎豹CS6lock基础之上再增多上面包车型地铁四个章程 

condition = threading.Condition([Lock/RLock]),暗中认可里面包车型的士参数是Wranglerlock

 

wait():条件不满足时调用,释放线程并跻身等待绿灯

notify():条件成立后调用,通告等待池激活叁个线程

notifyall():条件创建后调用,布告等待池激活全体线程

 

平昔上例子

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva
import threading,time
from random import randint

class producer(threading.Thread):
    '''
    生产者
    '''
    def run(self):
        global Li
        while True:
            value = randint(0,100) #创建一百以内随机数
            print('生产者',self.name,'Append:'+str(value),Li)
            if con.acquire(): #加锁
                Li.append(value) #把产品加入产品列表里
                con.notify()  #通知等待池里的消费者线程激活并运行
                con.release() #释放
            time.sleep(3)     #每3秒做一次产品

class consumer(threading.Thread):
    '''
    消费者
    '''
    def run(self):
        global Li
        while True:
            con.acquire() #获取条件变量锁,必须和生产者同一个锁对象,生产者通知后在此处开始运行
            if len(Li) == 0: #如果产品列表内没数据,表示消费者先抢到线程运行权
                con.wait()   #阻塞状态,等待生产者线程通知
            print('消费者',self.name,'Delete:'+str(Li [0]),Li)
            Li.remove(Li[0]) #删除被消费者用掉的产品
            con.release()    #释放
            time.sleep(0.5)  #每0.5秒用掉一个产品

con = threading.Condition() #创建条件变量锁对象
threads = [] #线程列表
Li = [] #产品列表

for i in range(5):
    threads.append(producer())

threads.append(consumer())

for i in threads:
    i.start()

for i in threads:
    i.join()

  

运作结果:

金沙注册送58 8

 

图表只截取了一部分,因为它直接在有线循环着的。这些生产者和买主的模子很杰出,必须驾驭,每一个步骤分别什么意思小编都注释了,不再赘述了。

 

直白调用threading模块 成立线程

Python中开创线程能够使用threading模块

  • threading.Thread(target=func,args = params,) 成立线程
    target钦赐施行的函数 target钦点参数元组方式

'''
python thread
'''
import threading

import time

beggin = time.time()


def foo(n):
    print('foo%s' % n)
    time.sleep(1)


def bar(n):
    print('bar %s' % n)


end = time.time()
cast_time = end - beggin
print(float(cast_time))
# 创建线程
t1 = threading.Thread(target=foo, args=('thread1',))
t2 = threading.Thread(target=bar, args=('thread2',))
t1.start()
t2.start()

Python GIL(Global Interpreter Lock) 

CPython implementation detail: In CPython, due to the Global Interpreter
Lock, only one thread can execute Python code at once (even though
certain performance-oriented libraries might overcome this limitation).
If you want your application to make better use of the computational
resources of multi-core machines, you are advised to use
multiprocessing. However, threading is still an appropriate model if you
want to run multiple I/O-bound tasks simultaneously.

3、Semaphore(信号量)

Semaphore管理3个放权的计数器,
每当调用acquire()时内置计数器-一;
调用release() 时内置计数器+一;
计数器不可能小于0;当计数器为0时,acquire()将封堵线程直到别的线程调用release()。

实例:(同时唯有五个线程能够得到semaphore,即能够界定最加纳阿克拉接数为⑤):

 1 import threading
 2 import time
 3 
 4 semaphore = threading.Semaphore(5)
 5 
 6 def func():
 7     if semaphore.acquire():
 8         print (threading.currentThread().getName() + ' get semaphore')
 9         time.sleep(2)
10         semaphore.release()
11 
12 for i in range(20):
13   t1 = threading.Thread(target=func)
14   t1.start()

 

11.event事件

 类似于condition,但它并不是二个线程锁,并且未有锁的功力

event = threading.伊芙nt(),条件蒙受目的,起初值为False

 

event.isSet():再次回到event的动静值

event.wait():如果event.isSet()的值为False将阻塞

event.set():设置event的图景值为True,全数阻塞池的线程激活并进入就绪状态,等待操作系统调节

event.clear():恢复生机event的情事值False

 

不多说,看3个事例:

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva

import threading,time

class boss(threading.Thread):
    def run(self):
        print('boss:今晚加班!')
        event.isSet() or event.set() #设置为True
        time.sleep(5)   #切换到员工线程
        print('boss:可以下班了')
        event.isSet() or event.set() #又设置为True


class worker(threading.Thread):
    def run(self):
        event.wait() #等待老板发话,只有值为True再往下走
        print('worker:唉~~~,又加班')
        time.sleep(1) #开始加班
        event.clear() #设置标志为false
        event.wait()  #等老板发话
        print('worker:oh yeah,终于可以回家了')


event = threading.Event()
threads = []
for i in range(5):
    threads.append(worker())
threads.append(boss())

for i in threads:
    i.start()

for i in threads:
    i.join()

  

 

运作结果:

金沙注册送58 9

 

实则那些和condition的通讯原理是同一的,只是condition用的是notify,event用的set和isset

经过持续threading模块调用线程

import threading
import time


class MyThread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):#定义每个线程要运行的函数

        print("running on number:%s" %self.num)

        time.sleep(3)

if __name__ == '__main__':

    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()
  • 开创类承接threading.Thread
  • 重写类的run方法

threading模块

4、Event对象

  线程的二个入眼本性是各类线程都是单独运维且情状不行预测。要是程序中的别的线程须求经过剖断某些线程的场地来分明自个儿下一步的操作,那时线程同步难点就
会变得卓殊费劲。

  为了消除这个标题,大家须要动用threading库中的伊芙nt对象。伊夫nt对象涵盖1个可由线程设置的复信号标识,它同意线程等待某个事件的产生。

  在
开始意况下,伊芙nt对象中的频限信号标记棉被服装置为假。假使无线程等待一个伊芙nt对象,
而那个伊芙nt对象的表明为假,那么这一个线程将会被一向不通直至该标记为真。二个线程假使将3个伊芙nt对象的时域信号标识设置为真,它将唤起全部等待那一个伊夫nt对象的线程。若是2个线程等待八个曾经棉被服装置为确实伊芙nt对象,那么它将忽略这个事件,
继续实践

event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

 

用evnt对象模拟红绿灯:

import queue,threading,time
import random

event = threading.Event()
def light():
    while True:
        event.set()
        for i in range(10):
            print('light green')
            time.sleep(1)
        event.clear()
        for i in range(10,13):
            print('light yellow')
            time.sleep(1)
        for i in range(13,21):
            print('light red')
            time.sleep(1)

def car(i):
    while True:
        time.sleep(random.randint(1,5))
        if event.isSet():
            print('car %s is runing'%i)
        else:
            print('car %s is waiting'%i)

if __name__ == '__main__':
    l1=threading.Thread(target=light)
    l1.start()

    for i in range(5):
        i = threading.Thread(target=car,args=(i,))
        i.start()

 

Python 八线程中的GIL

Python的GIL并不是Python的特点,它是在落成Python解析器也便是依照C语言的解析器
CPython时所引进的三个定义。Python能够用不一致的编写翻译器来编写翻译成可进行代码。比方C语言中的GCC等。也正是说唯有在CPython中才会现身GIL的意况
GIL又称之为全局解释器锁(Global Interpreter Lock)
今世的CPU已经是多核CPU,为了更实用的施用多核管理器的属性,就应运而生了十②线程的编制程序格局。而在化解四线程之间数据完整性和景况同步的最简单易行的措施正是加锁。GIL正是给Python解释器加了1把大锁。我们知晓Python是由解释器实施的,由于GIL的留存
只可以有三个线程被解释器实施,那样就使得Python在10二线程实践上的成效变低。由于历史遗留难题,发现大量库代码开荒者现已重度正视GIL而卓殊不便去除了。也正是说在多核CPU上,并行试行的Python八线程,乃至不比串行实行的Python程序,那正是GIL存在的难题

壹 线程的二种调用格局

直接调用

实例1:

金沙注册送58 10

金沙注册送58 11

import threading
import time

def sayhi(num): #定义每个线程要运行的函数

    print("running on number:%s" %num)

    time.sleep(3)

if __name__ == '__main__':

    t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
    t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例

    t1.start() #启动线程
    t2.start() #启动另一个线程

    print(t1.getName()) #获取线程名
    print(t2.getName())

金沙注册送58 12

继承式调用:

金沙注册送58 13

金沙注册送58 14

import threading
import time


class MyThread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):#定义每个线程要运行的函数

        print("running on number:%s" %self.num)

        time.sleep(3)

if __name__ == '__main__':

    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()

金沙注册送58 15

4、队列(queue)

”’

始建1个“队列”对象

import queueq
q = queue.Queue(maxsize = 10)
    #queue.Queue类就是二个行列的共同完结。队列长度可为Infiniti可能个别。可通过Queue的构造函数的可选参数
    #maxsize来设定队列长度。借使maxsize小于1就表示队列长度Infiniti。

q.put()    将四个值2二放入队列中

    #调用队列对象的put()方法在队尾插入多个体系。put()有三个参数,第叁个item为须要的,为插入项目标值;第3个block为可选参数,暗中认可为1。要是队列当前为空且block为1,put()方法就使调用线程暂停,直到空出贰个数额单元。要是block为0,put方法将抓住Full至极。

q.get()    将1个值从队列中收取    

    #调用队列对象的get()方法从队头删除并重返贰个品种。可选参数为block,默以为True。借使队列为空且block为True,get()就使调用线程暂停,直至有档案的次序可用。即便队列为空且block为False,队列将引发Empty至极。

”’

queue的常用方法

'''

此包中的常用方法(q = Queue.Queue()):

q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)非阻塞 
q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作

'''

*12.队列(queue)

实为上,队列是2个数据结构。

 

一)成立四个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类便是一个队列的一道完成。队列长度可为无限大概个别。可经过Queue的构造函数的可选参数maxsize来设定队列长度。若是maxsize小于一就代表队列长度Infiniti。

二)将贰个值放入队列中
q.put(obj)
调用队列对象的put()方法在队尾插入三个品种。put()有多个参数,第3个item为必要的,为插入项目标值;第1个block为可选参数,默以为
1。如若队列当前为空且block为1,put()方法就使调用线程暂停,直到空出贰个数目单元。借使block为0,put方法将抓住Full格外。

三)将三个值从队列中收取
q.get()
调用队列对象的get()方法从队头删除并重返一个项目。可选参数为block,默感到True。借使队列为空且block为True,get()就使调用线程暂停,直至有档期的顺序可用。假如队列为空且block为False,队列将引发Empty万分。

 

例:

金沙注册送58 16

 

 

四)Python Queue模块有三种队列及构造函数:

  • Python Queue模块的FIFO队列先进先出    class queue.Queue(maxsize)
  • LIFO类似于堆,即先进后出        class
    queue.LifoQueue(maxsize)
  • 还有一种是预先级队列等第越低越先出来  class
    queue.PriorityQueue(maxsize)

 

当maxsize值比put的数码少时就会阻塞住,当数码被get后留有空间才干跟着put进去,接近于线程的频限信号量

金沙注册送58 17

 

 

伍)queue中的常用方法(q = Queue.Queue()):
q.qsize():重返队列的大大小小
q.empty():若是队列为空,重回True,反之False
q.full():如若队列满了,重临True,反之False,q.full与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait():相当q.get(False)
q.put_nowait(item):相当q.put(item, False)
q.task_done():在产生壹项专门的学问之后,q.task_done()
函数向任务现已成功的种类发送贰个时限信号
q.join():实际上意味着等到队列为空,再推行别的操作

 

陆)队列有哪些便宜,与列表分化

队列本人就有壹把锁,内部已经维持1把锁,倘若您用列表的话,当情状是在八线程下,那么列表数据就势必会有争辩,而队列不会,因为此,队列有个绰号——二十四线程利器

例:

#!usr/bin/env python
#-*- coding:utf-8 -*-

# author:yangva

import threading,time
import queue
from random import randint

class productor(threading.Thread):
    def run(self):
        while True:
            r = randint(0,100)
            q.put(r)
            print('生产出来 %s 号产品'%r)
            time.sleep(1)

class consumer(threading.Thread):
    def run(self):
        while True:
            result =q.get()
            print('用掉 %s 号产品'%result)
            time.sleep(1)

q = queue.Queue(10)
threads = []
for i in range(3):
    threads.append(productor())

threads.append(consumer())

for i in threads:
    i.start()

  

运维结果:

金沙注册送58 18

 

那边素有无须加锁就完了了前头的劳动者消费者模型,因为queue里面自带了一把锁。

 

好的,关于线程的知识点,批注完。

 

Python GIL的出现处境

在Python中要是任务是IO密集型的,能够利用102线程。而且Python的二十四线程13分擅长管理那种难点
而一旦Python中只要职责是测算密集型的,就须要管理一下GIL

二 Join & Daemon

金沙注册送58 19

金沙注册送58 20

import threading
from time import ctime,sleep
import time

def music(func):
    for i in range(2):
        print ("Begin listening to %s. %s" %(func,ctime()))
        sleep(4)
        print("end listening %s"%ctime())

def move(func):
    for i in range(2):
        print ("Begin watching at the %s! %s" %(func,ctime()))
        sleep(5)
        print('end watching %s'%ctime())

threads = []
t1 = threading.Thread(target=music,args=('七里香',))
threads.append(t1)
t2 = threading.Thread(target=move,args=('阿甘正传',))
threads.append(t2)

if __name__ == '__main__':

    for t in threads:
        # t.setDaemon(True)
        t.start()
        # t.join()
    # t1.join()
    t2.join()########考虑这三种join位置下的结果?
    print ("all over %s" %ctime())

金沙注册送58 21

setDaemon(True):

      将线程申明为照应线程,必须在start() 方法调用在此之前安装,
如若不设置为护理线程程序会被无限挂起。那些办法基本和join是相反的。当我们在程序运营中,实施一个主线程,如果主线程更创办2个子线程,主线程和子线程
就分兵两路,分别运营,那么当主线程达成想退出时,会查证子线程是或不是完结。若是子线程未形成,则主线程会等待子线程落成后再脱离。但是有时大家须求的是
只要主线程完结了,不管仲线程是或不是变成,都要和主线程一同退出,那时就能够用setDaemon方法啦 

join():

       在子线程实现运维在此之前,那几个子线程的父线程将直接被堵塞。

其他格局

金沙注册送58 22

金沙注册送58 23

thread 模块提供的其他方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
# 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
# run(): 用以表示线程活动的方法。
# start():启动线程活动。
# join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。

金沙注册送58 24

join与task_done方法

'''
join() 阻塞进程,直到所有任务完成,需要配合另一个方法task_done。

    def join(self):
     with self.all_tasks_done:
      while self.unfinished_tasks:
       self.all_tasks_done.wait()

task_done() 表示某个任务完成。每一条get语句后需要一条task_done。


import queue
q = queue.Queue(5)
q.put(10)
q.put(20)
print(q.get())
q.task_done()
print(q.get())
q.task_done()

q.join()

print("ending!")
'''

10二线程式爬虫

一对朋友学完线程还不了解线程到底能选用于怎么样生活实在,好的,不多说,来,大家爬下堆糖网()的校花照片。

 

import requests
import urllib.parse
import threading,time,os

#设置照片存放路径
os.mkdir('duitangpic')
base_path = os.path.join(os.path.dirname(__file__),'duitangpic')

#设置最大信号量线程锁
thread_lock=threading.BoundedSemaphore(value=10)

#通过url获取数据
def get_page(url):
    header={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    page=requests.get(url,headers=header)
    page=page.content #content是byte
    #转为字符串
    page=page.decode('utf-8')
    return page

#label  即是搜索关键词
def page_from_duitang(label):
    pages=[]
    url='https://www.duitang.com/napi/blog/list/by_search/?kw={}&start={}&limit=1000'
    label=urllib.parse.quote(label)#将中文转成url(ASCII)编码
    for index in range(0,3600,100):
        u=url.format(label,index)
        #print(u)
        page=get_page(u)
        pages.append(page)
    return pages

def findall_in_page(page,startpart,endpart):
    all_strings=[]
    end=0
    while page.find(startpart,end) !=-1:
        start=page.find(startpart,end)+len(startpart)
        end=page.find(endpart,start)
        string=page[start:end]
        all_strings.append(string)

    return all_strings

def pic_urls_from_pages(pages):
    pic_urls=[]
    for page in pages:
        urls=findall_in_page(page,'path":"','"')
        #print('urls',urls)
        pic_urls.extend(urls)
    return pic_urls

def download_pics(url,n):
    header={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    r=requests.get(url,headers=header)
    path=base_path+'/'+str(n)+'.jpg'
    with open(path,'wb') as f:
        f.write(r.content)
    #下载完,解锁
    thread_lock.release()

def main(label):
    pages=page_from_duitang(label)
    pic_urls=pic_urls_from_pages(pages)
    n=0
    for url in pic_urls:
        n+=1
        print('正在下载第{}张图片'.format(n))
        #上锁
        thread_lock.acquire()
        t=threading.Thread(target=download_pics,args=(url,n))
        t.start()
main('校花')

  

运营结果:

金沙注册送58 25

 

在与本py文件壹律的目录下,有个duitangpic的公文夹,张开看看:

金沙注册送58 26

 

 全是仙女,而且不出意外又好几千张呢,作者那唯有一千多张是因为自个儿手动结束了py程序运转,究竟本人那是出现说法,不须要真正等程序运转完。我大意预计,不出意外应该能爬到2000张左右的照片

 

如何,老铁,得劲不?刺不激情?感受到二10四线程的用处了不?而且那恐怕python下的伪八线程(IO密集型,但并不算是真正含义上的八线程),你用其余的语言来爬更充沛。

 

join 和daemon

join

  • 在子线程落成运维从前,那些子线程的父线程将直接被卡住。在二个主次中大家实行一个主线程,这几个主线程更创办二个子线程,主线程和子线程就竞相实践,当子线程在主线程中调用join方法时,主线程会等待子线程实行完后再甘休

'''in main thread'''
t.join() 主线程会等待线程t执行完成后再继续执行

daemon

  • setDaemon(true)
    将线程证明为守护线程,必须在start() 方法调用在此以前设置,
    假设不安装为照应线程程序会被无限挂起。那一个措施基本和join是倒转的。当大家在程序运营中,实行一个主线程,假若主线程再次创下办2个子线程,主线程和子线程
    就分兵两路,分别运维,那么当主线程达成想淡出时,会核准子线程是还是不是到位。借使子线程未成功,则主线程会等待子线程完毕后再脱离。然而有时大家须求的是
    只要主线程达成了,不管仲线程是否完结,都要和主线程一齐退出,那时就足以
    用setDaemon方法啦
  • currentThread() 获取当前实行的线程

三 同步锁(Lock)

金沙注册送58 27

import time
import threading

def addNum():
    global num #在每个线程中都获取这个全局变量
    # num-=1

    temp=num
    print('--get num:',num )
    #time.sleep(0.1)
    num =temp-1 #对此公共变量进行-1操作


num = 100  #设定一个共享变量
thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list: #等待所有线程执行完毕
    t.join()

print('final num:', num )

金沙注册送58 28

 

 

金沙注册送58 29

 

注意:

一:  why num-=壹没问题吗?那是因为动作太快(完结那么些动作在切换的岁月内)

二: if
sleep(一),现象会更显著,96个线程每2个一定都未有实践完就展开了切换,大家说过sleep就等效于IO阻塞,1s以内不会再切换回来,所以最后的结果确定是99.

 

四个线程都在同时操作同三个共享能源,所以导致了财富破坏,如何做呢?

有同学会想用join呗,但join会把全路径程给停住,形成了串行,失去了10二线程的意义,而大家只须要把计算(涉及到操作公共数据)的时候串行实施。

咱俩得以由此同步锁来减轻那种主题素材

金沙注册送58 30

import time
import threading

def addNum():
    global num #在每个线程中都获取这个全局变量
    # num-=1
    lock.acquire()
    temp=num
    print('--get num:',num )
    #time.sleep(0.1)
    num =temp-1 #对此公共变量进行-1操作
    lock.release()

num = 100  #设定一个共享变量
thread_list = []
lock=threading.Lock()

for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list: #等待所有线程执行完毕
    t.join()

print('final num:', num )

金沙注册送58 31

标题一蹴即至,但

请问:同步锁与GIL的涉及?

Python的线程在GIL的决定之下,线程之间,对全数python解释器,对python提供的C
API的造访都以排斥的,这足以视作是Python内核级的排外机制。可是那种互斥是大家无法调整的,我们还要求其它一种可控的排斥机制———用户级互斥。内核级通过互斥爱护了基础的共享能源,一样,用户级互斥珍重了用户程序中的共享财富。

GIL
的功能是:对于3个解释器,只可以有多少个thread在施行bytecode。所以每时每刻唯有一条bytecode在被推行2个thread。GIL有限支持了bytecode
那层面上是thread safe的。
而是只要您有个操作比如 x +=
1,这么些操作需求多个bytecodes操作,在实行那一个操作的多条bytecodes时期的时候可能中途就换thread了,那样就应运而生了data
races的景况了。

 

那本人的一路锁也是承接保险平等时刻只有一个线程被实行,是还是不是未有GIL也足以?是的;那要GIL有啥样鸟用?你没治;

queue的三种方式:

壹、queue.Queue()  先进先出情势

贰、queue.LifoQueue()    先进后出,类似栈

三、queue.PriorityQueue()  
优先级格局,优先级越高越先出,数字月首代表优先级越高

import queue

#######################先进后出
q=queue.LifoQueue()

q.put(34)
q.put(56)
q.put(12)

#####################优先级
q=queue.PriorityQueue()
q.put([5,100])
q.put([7,200])
q.put([3,"hello"])
q.put([4,{"name":"alex"}])

while 1:
  data=q.get()
  print(data)

线程中的锁

先看2个线程共享数据的主题素材

'''
线程安全问题
'''
# 定义一个共享变量
import threading

import time

num = 100


def sub():
    # 操作类变量
    global num
    tmp = num
    time.sleep(0.1)
    num = tmp - 1


if __name__ == '__main__':
    thread_list = []
    for i in range(100):
        t1 = threading.Thread(target=sub)
        t1.start()
        thread_list.append(t1)
    for i in range(100):
        t2 = thread_list[i]
        t2.join()

print('final num' + str(num))
>>> 
final num99

肆 线程死锁和递归锁

     
在线程间共享八个能源的时候,假使四个线程分别攻克1部分能源并且还要等待对方的财富,就会导致死锁,因为系统决断那有个别财富都正在使用,全数那三个线程在无外力成效下将直接等候下去。上边是三个死锁的例证:

金沙注册送58 32

金沙注册送58 33

import threading,time

class myThread(threading.Thread):
    def doA(self):
        lockA.acquire()
        print(self.name,"gotlockA",time.ctime())
        time.sleep(3)
        lockB.acquire()
        print(self.name,"gotlockB",time.ctime())
        lockB.release()
        lockA.release()

    def doB(self):
        lockB.acquire()
        print(self.name,"gotlockB",time.ctime())
        time.sleep(2)
        lockA.acquire()
        print(self.name,"gotlockA",time.ctime())
        lockA.release()
        lockB.release()
    def run(self):
        self.doA()
        self.doB()
if __name__=="__main__":

    lockA=threading.Lock()
    lockB=threading.Lock()
    threads=[]
    for i in range(5):
        threads.append(myThread())
    for t in threads:
        t.start()
    for t in threads:
        t.join()#等待线程结束,后面再讲。

金沙注册送58 34

化解办法:使用递归锁,将

1
2
lockA=threading.Lock()
lockB=threading.Lock()<br>#--------------<br>lock=threading.RLock()

为了帮助在同一线程中1再请求同一能源,python提供了“可重入锁”:threading.昂CoraLock。HavalLock内部维护着叁个Lock和三个counter变量,counter记录了acquire的次数,从而使得财富得以被数十次acquire。直到3个线程全数的acquire都被release,别的的线程手艺博取财富。

应用

金沙注册送58 35

金沙注册送58 36

import time

import threading

class Account:
    def __init__(self, _id, balance):
        self.id = _id
        self.balance = balance
        self.lock = threading.RLock()

    def withdraw(self, amount):

        with self.lock:
            self.balance -= amount

    def deposit(self, amount):
        with self.lock:
            self.balance += amount


    def drawcash(self, amount):#lock.acquire中嵌套lock.acquire的场景

        with self.lock:
            interest=0.05
            count=amount+amount*interest

            self.withdraw(count)


def transfer(_from, to, amount):

    #锁不可以加在这里 因为其他的其它线程执行的其它方法在不加锁的情况下数据同样是不安全的
     _from.withdraw(amount)

     to.deposit(amount)



alex = Account('alex',1000)
yuan = Account('yuan',1000)

t1=threading.Thread(target = transfer, args = (alex,yuan, 100))
t1.start()

t2=threading.Thread(target = transfer, args = (yuan,alex, 200))
t2.start()

t1.join()
t2.join()

print('>>>',alex.balance)
print('>>>',yuan.balance)

金沙注册送58 37

队列的利用:生产者消费者模型

  在线程世界里,生产者正是生育数量的线程,消费者正是开支数量的线程。在多线程开采当中,要是劳动者管理速度一点也不慢,而顾客管理速度极慢,那么生产者就不能够不等待买主管理完,本事持续生产数据。同样的道理,要是顾客的拍卖才具超过生产者,那么消费者就务须待产者。为了缓和这些问题于是引进了劳动者和顾客形式。

  生产者消费者格局是通过1个器皿来缓和劳动者和顾客的强耦合难点。生产者和消费者相互之间不直接通信,而通过阻塞队列来开始展览报纸发表,所以生产者生产完数据未来并非等待买主管理,直接扔给卡住队列,消费者不找生产者要多少,而是直接从绿灯队列里取,闭塞队列就一定于一个缓冲区,平衡了劳动者和买主的拍卖才能。

  那就如,在客栈,厨师做好菜,不需求一向和客户交换,而是交由前台,而客户去饭菜也不供给不找大厨,直接去前台领取就能够,那也是3个结耦的进程。

import queue,threading,time
import random

q = queue.Queue(50)

def Producer():
    while True:
        if q.qsize() < 20:
            n = random.randint(1, 100)
            q.put(n)
            print(" has made baozi %s" % n)
            time.sleep(1)

def Consumer(id):
    while True:
         s = q.get()
         print("Consumer"+id+"has eat %s" % s)
         time.sleep(2)

for i in range(5):
    t1=threading.Thread(target=Producer,args=())
    t1.start()

for i in range(2):
    t=threading.Thread(target=Consumer,args=(str(i),))
    t.start()

  

  

 

分析

地方的顺序中,大家想要的是打开9十八个线程,各种线程将共享数据减去1,可是大家开采输出的结果是9玖,那种气象是因为多线程在cpu中推行时是抢占式的,程序在始发实践时,开启了九二十一个线程去施行,当程序推行到time.sleep(0.1)时,由于发生了线程的隔开分离,所以cpu举办了切换,此时,程序的共享变量num是100,中间变量tmp也是十0
在线程阻塞过后,将共享变量num的值减一,值变为9玖此时其余的线程获得cpu的试行机会,而日前线程中的共享变量num的值仍旧100所以试行减一操作后,又将中间值赋值给共享变量num所以num的值平昔为99

  • 线程的执市场价格况
![](https://upload-images.jianshu.io/upload_images/6052465-461749d8c9eb7ea5.png)

多线程抢占.png

5 条件变量同步(Condition)

     
有壹类线程必要满意条件之后才具够继续实施,Python提供了threading.Condition
对象用于标准变量线程的支撑,它除了能提供TiggoLock()或Lock()的措施外,还提供了
wait()、notify()、notifyAll()方法。

      lock_con=threading.Condition([Lock/Rlock]):
锁是可选选项,不传人锁,对象活动成立二个奥迪Q5Lock()。

wait():条件不满足时调用,线程会释放锁并进入等待阻塞;
notify():条件创造后调用,通知等待池激活一个线程;
notifyAll():条件创造后调用,通知等待池激活所有线程。

实例

金沙注册送58 38

金沙注册送58 39

import threading,time
from random import randint
class Producer(threading.Thread):
    def run(self):
        global L
        while True:
            val=randint(0,100)
            print('生产者',self.name,":Append"+str(val),L)
            if lock_con.acquire():
                L.append(val)
                lock_con.notify()
                lock_con.release()
            time.sleep(3)
class Consumer(threading.Thread):
    def run(self):
        global L
        while True:
                lock_con.acquire()
                if len(L)==0:
                    lock_con.wait()
                print('消费者',self.name,":Delete"+str(L[0]),L)
                del L[0]
                lock_con.release()
                time.sleep(0.25)

if __name__=="__main__":

    L=[]
    lock_con=threading.Condition()
    threads=[]
    for i in range(5):
        threads.append(Producer())
    threads.append(Consumer())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

金沙注册送58 40

Python 同步锁

操作锁的主题在threading 模块中 Lock()

  • threading.Lock() 会获得壹把锁
  • Python 中使用acquire() 获得锁

r = threading.Lock()
# 加锁
r.acquire()
  • Python中使用release()释放锁

r.release()

加锁后代码

'''
线程安全问题
'''
# 定义一个共享变量
import threading
import time
num = 100
r = threading.Lock()
def sub():
    # 操作类变量
    global num
    r.acquire()
    tmp = num
    time.sleep(0.1)
    num = tmp - 1
    r.release()
if __name__ == '__main__':
    thread_list = []
    for i in range(100):
        t1 = threading.Thread(target=sub)
        t1.start()
        thread_list.append(t1)
    for i in range(100):
        t2 = thread_list[i]
        t2.join()
print('final num' + str(num))

六 同步条件(伊芙nt)

     
条件同步和准星变量同步差不离意思,只是少了锁成效,因为条件同步设计于不访问共享财富的口径情状。event=threading.伊夫nt():条件情况目的,先导值
为False;

金沙注册送58 41

event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

金沙注册送58 42

实例1:

金沙注册送58 43

金沙注册送58 44

import threading,time
class Boss(threading.Thread):
    def run(self):
        print("BOSS:今晚大家都要加班到22:00。")
        event.isSet() or event.set()
        time.sleep(5)
        print("BOSS:<22:00>可以下班了。")
        event.isSet() or event.set()
class Worker(threading.Thread):
    def run(self):
        event.wait()
        print("Worker:哎……命苦啊!")
        time.sleep(0.25)
        event.clear()
        event.wait()
        print("Worker:OhYeah!")
if __name__=="__main__":
    event=threading.Event()
    threads=[]
    for i in range(5):
        threads.append(Worker())
    threads.append(Boss())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

金沙注册送58 45

实例2:

金沙注册送58 46

金沙注册送58 47

import threading,time
import random
def light():
    if not event.isSet():
        event.set() #wait就不阻塞 #绿灯状态
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if event.isSet():
                event.clear()
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            event.set() #打开绿灯
        time.sleep(1)
        count +=1
def car(n):
    while 1:
        time.sleep(random.randrange(10))
        if  event.isSet(): #绿灯
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()

金沙注册送58 48

线程中的死锁和递归锁

在线程间共享多少个能源的时候,假设七个线程分别攻克壹部分能源并且还要等待对方释放对方的能源,就会导致死锁,因为系统剖断这有些能源正在使用,所以那四个线程在无外力功用下将直接等候下去
看个栗子:

'''
线程死锁
'''

import threading, time


class myThread(threading.Thread):
    def doA(self):
        lockA.acquire()
        print(self.name, "gotlockA", time.ctime())
        time.sleep(3)
        lockB.acquire()
        print(self.name, "gotlockB", time.ctime())
        lockB.release()
        lockA.release()

    def doB(self):
        lockB.acquire()
        print(self.name, "gotlockB", time.ctime())
        time.sleep(2)
        lockA.acquire()
        print(self.name, "gotlockA", time.ctime())
        lockA.release()
        lockB.release()

    def run(self):
        self.doA()
        self.doB()


if __name__ == "__main__":

    lockA = threading.Lock()
    lockB = threading.Lock()

    threads = []
    for i in range(5):
        threads.append(myThread())
    for t in threads:
        t.start()
    for t in threads:
        t.join()  # 等待线程结束,后面再讲。

在上述程序中,四个线程互对峙有对方的锁并且等待对方释放,那就形成了死锁

七 信号量(Semaphore)

     
时域信号量用来调节线程并发数的,Bounded塞马phore或Semaphore管理多少个内置的计数
器,每当调用acquire()时-壹,调用release()时+一。

      计数器不可能小于0,当计数器为
0时,acquire()将阻塞线程至二头锁定状态,直到其他线程调用release()。(类似于停车位的概念)

     
BoundedSemaphore与Semaphore的绝无仅有差别在于前者将要调用release()时检查计数
器的值是还是不是超越了计数器的始发值,假设超越了将抛出叁个卓殊。

实例:

金沙注册送58 49

金沙注册送58 50

import threading,time
class myThread(threading.Thread):
    def run(self):
        if semaphore.acquire():
            print(self.name)
            time.sleep(5)
            semaphore.release()
if __name__=="__main__":
    semaphore=threading.Semaphore(5)
    thrs=[]
    for i in range(100):
        thrs.append(myThread())
    for t in thrs:
        t.start()

金沙注册送58 51

消除死锁的情势

  • threading.本田UR-VLock() 可重入锁
    为了帮助在同一线程中一再请求同壹财富,python提供了“可重入锁”:threading.KugaLock。昂科威Lock内部维护着一个Lock和多个counter变量,counter记录了acquire的次数,从而使得财富能够被数十四回acquire。直到1个线程全部的acquire都被release,别的的线程才具获得能源。可重入锁的里边维持了一个计数器和锁对象。

 8 十二线程利器(queue)

     queue is especially useful in threaded programming when information
must be exchanged safely between multiple threads.

信号量

实信号量用来支配线程并发数的,BoundedSemaphore或Semaphore处理二个置于的计数器,每当调用acquire()时-一,调用release()时+1
计数器无法小于0当计数器为0时,acquire()将阻塞线程至三头锁定状态,直到其余线程调用release()。
BoundedSemaphore与Semaphore的唯一差距在于前者将要调用release()时检查计数器的值是还是不是抢先了计数器的开头值。如若赶上了将抛出二个格外

queue列队类的法子

金沙注册送58 52

开创多个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类正是三个行列的共同完成。队列长度可为Infiniti大概简单。可由此Queue的构造函数的可选参数maxsize来设定队列长度。要是maxsize小于壹就象征队列长度Infiniti。

将多个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入二个连串。put()有四个参数,第2个item为须要的,为插入项目标值;第三个block为可选参数,默以为
一。借使队列当前为空且block为1,put()方法就使调用线程暂停,直到空出1个数据单元。假设block为0,put方法将吸引Full非常。

将一个值从队列中抽取
q.get()
调用队列对象的get()方法从队头删除并赶回多少个连串。可选参数为block,默认为True。假诺队列为空且block为True,get()就使调用线程暂停,直至有品种可用。要是队列为空且block为False,队列将引发Empty十分。

Python Queue模块有两种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。  class queue.Queue(maxsize)
贰、LIFO类似于堆,即先进后出。             class
queue.LifoQueue(maxsize)
三、还有一种是先行级队列品级越低越先出来。   class
queue.PriorityQueue(maxsize)

此包中的常用方法(q = Queue.Queue()):
q.qsize() 重返队列的高低
q.empty() 倘若队列为空,重回True,反之False
q.full() 假使队列满了,重临True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在成就1项专门的学问之后,q.task_done()
函数向职分现已产生的队列发送2个随机信号
q.join() 实际上意味着等到队列为空,再试行其他操作

金沙注册送58 53

成立频限信号量

  • threading.BoundedSemaphore(num) 指定期限信号量为num

import threading

import time


class Mythread(threading.Thread):
    def run(self):
        # 判断是否加锁
        if semaphore.acquire():
            print(self.name)
            time.sleep(1)
            # 释放锁
            semaphore.release()


if __name__ == '__main__':
    # 创建带有信号量的锁
    semaphore = threading.BoundedSemaphore(5)
    # 存放线程的序列
    thrs = []
    for i in range(100):
        thrs.append(Mythread())
    for t in thrs:
        t.start()

实例

实例1:

金沙注册送58 54

金沙注册送58 55

import threading,queue
from time import sleep
from random import randint
class Production(threading.Thread):
    def run(self):
        while True:
            r=randint(0,100)
            q.put(r)
            print("生产出来%s号包子"%r)
            sleep(1)
class Proces(threading.Thread):
    def run(self):
        while True:
            re=q.get()
            print("吃掉%s号包子"%re)
if __name__=="__main__":
    q=queue.Queue(10)
    threads=[Production(),Production(),Production(),Proces()]
    for t in threads:
        t.start()

金沙注册送58 56

实例2:

金沙注册送58 57

金沙注册送58 58

import time,random
import queue,threading
q = queue.Queue()
def Producer(name):
  count = 0
  while count <20:
    time.sleep(random.randrange(3))
    q.put(count)
    print('Producer %s has produced %s baozi..' %(name, count))
    count +=1
def Consumer(name):
  count = 0
  while count <20:
    time.sleep(random.randrange(4))
    if not q.empty():
        data = q.get()
        print(data)
        print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
    else:
        print("-----no baozi anymore----")
    count +=1
p1 = threading.Thread(target=Producer, args=('A',))
c1 = threading.Thread(target=Consumer, args=('B',))
p1.start()
c1.start()

金沙注册送58 59

实例3:

金沙注册送58 60

金沙注册送58 61

#实现一个线程不断生成一个随机数到一个队列中(考虑使用Queue这个模块)
# 实现一个线程从上面的队列里面不断的取出奇数
# 实现另外一个线程从上面的队列里面不断取出偶数

import random,threading,time
from queue import Queue
#Producer thread
class Producer(threading.Thread):
  def __init__(self, t_name, queue):
    threading.Thread.__init__(self,name=t_name)
    self.data=queue
  def run(self):
    for i in range(10):  #随机产生10个数字 ,可以修改为任意大小
      randomnum=random.randint(1,99)
      print ("%s: %s is producing %d to the queue!" % (time.ctime(), self.getName(), randomnum))
      self.data.put(randomnum) #将数据依次存入队列
      time.sleep(1)
    print ("%s: %s finished!" %(time.ctime(), self.getName()))

#Consumer thread
class Consumer_even(threading.Thread):
  def __init__(self,t_name,queue):
    threading.Thread.__init__(self,name=t_name)
    self.data=queue
  def run(self):
    while 1:
      try:
        val_even = self.data.get(1,5) #get(self, block=True, timeout=None) ,1就是阻塞等待,5是超时5秒
        if val_even%2==0:
          print ("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(),self.getName(),val_even))
          time.sleep(2)
        else:
          self.data.put(val_even)
          time.sleep(2)
      except:   #等待输入,超过5秒 就报异常
        print ("%s: %s finished!" %(time.ctime(),self.getName()))
        break
class Consumer_odd(threading.Thread):
  def __init__(self,t_name,queue):
    threading.Thread.__init__(self, name=t_name)
    self.data=queue
  def run(self):
    while 1:
      try:
        val_odd = self.data.get(1,5)
        if val_odd%2!=0:
          print ("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(), self.getName(), val_odd))
          time.sleep(2)
        else:
          self.data.put(val_odd)
          time.sleep(2)
      except:
        print ("%s: %s finished!" % (time.ctime(), self.getName()))
        break
#Main thread
def main():
  queue = Queue()
  producer = Producer('Pro.', queue)
  consumer_even = Consumer_even('Con_even.', queue)
  consumer_odd = Consumer_odd('Con_odd.',queue)
  producer.start()
  consumer_even.start()
  consumer_odd.start()
  producer.join()
  consumer_even.join()
  consumer_odd.join()
  print ('All threads terminate!')

if __name__ == '__main__':
  main()

金沙注册送58 62

只顾:列表是线程不安全的

金沙注册送58 63

金沙注册送58 64

import threading,time

li=[1,2,3,4,5]

def pri():
    while li:
        a=li[-1]
        print(a)
        time.sleep(1)
        try:
            li.remove(a)
        except:
            print('----',a)

t1=threading.Thread(target=pri,args=())
t1.start()
t2=threading.Thread(target=pri,args=())
t2.start()

金沙注册送58 65

基准变量同步

有一类线程供给满足条件之后本事够继续推行,Python提供了threading.Condition
对象用于标准变量线程的帮衬,它除了能提供ENCORELock()或Lock()的方法外,还提供了
wait()、notify()、notifyAll()方法。
条件变量也是线程中的一把锁,可是规格变量能够兑现线程间的通讯,类似于Java中的唤醒和等候

九 Python中的上下文管理器(contextlib模块)

上下文管理器的职分是:代码块实施前妄想,代码块实践后处置

创办规范变量锁

  • lock_con = threading.Condition(Lock/奥迪Q5lock)
    锁是可选选项,不扩散锁对象活动创立一个PRADOLock()
  • wait() 条件不满意时调用,线程会自由锁并跻身等待绿灯
  • notify() 条件成立后调用,通告等待池激活2个线程
  • notifyAll() 条件创立后调用,公告等待池激活全体线程
    看个栗子

'''
线程条件变量
'''
import threading
from random import randint

import time


class Producer(threading.Thread):
    def run(self):
        global L
        while True:
            val = randint(0, 100)
            print('生产者', self.name, ':Append' + str(val), L)
            if lock_con.acquire():
                L.append(val)
                lock_con.notify()
                lock_con.release()
            time.sleep(3)


class Consumer(threading.Thread):
    def run(self):
        global L
        while True:
            lock_con.acquire()
            if len(L) == 0:
                lock_con.wait()
            print('消费者',self.name,"Delete"+str(L[0]),L)
            del  L[0]
            lock_con.release()
            time.sleep(0.25)


if __name__ == '__main__':
    L = []
    # 创建条件变量锁
    lock_con = threading.Condition()
    # 线程存放列表
    threads = []
    for i in range(5):
        threads.append(Producer())
    threads.append(Consumer())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

一、怎么着使用上下文管理器:

怎么开发二个文本,并写入”hello world”

1
2
3
4
5
filename="my.txt"
mode="w"
f=open(filename,mode)
f.write("hello world")
f.close()

当发生尤其时(如磁盘写满),就未有机会施行第伍行。当然,我们得以接纳try-finally语句块举行包装:

1
2
3
4
5
writer=open(filename,mode)
try:
    writer.write("hello world")
finally:
    writer.close()

当我们开始展览复杂的操作时,try-finally语句就会变得丑陋,采用with语木帝写:

1
2
with open(filename,mode) as writer:
    writer.write("hello world")

as指代了从open()函数再次来到的剧情,并把它赋给了新值。with落成了try-finally的任务。

壹块条件event

条件同步和标准化变量同步大概意思,只是少了锁作用,因为条件同步设计于不访问共享财富的尺度情况。event=threading.伊芙nt():条件处境目标,发轫值
为False;

  • event.isSet():再次回到event的图景值;

  • event.wait():借使 event.isSet()==False将阻塞线程;

  • event.set():
    设置event的处境值为True,全体阻塞池的线程激活进入就绪状态,
    等待操作系统调整;

  • event.clear():苏醒event的场地值为False。
    举个栗子:

'''
同步条件event
'''
import threading

import time


class Boss(threading.Thread):
    def run(self):
        print('BOSS: 今晚加班')
        # 改变事件
        event.isSet() or event.set()
        time.sleep(5)
        print('BOSS:加班结束')
        event.isSet() or event.set()


class Worker(threading.Thread):
    def run(self):
        event.wait()
        print('WORKER:OH NO')
        time.sleep(0.25)
        # 改变同步事件标志
        event.clear()
        event.wait()
        print('WORKER:OH YEAD!')

if __name__ == '__main__':
    # 获取同步事件
    event = threading.Event()
    threads = []
    for i in range(5):
        threads.append(Worker())
    threads.append(Boss())
    for t in threads:
        t.start()
    for t in threads:
        t.join()

二、自定义上下文管理器  

with语句的职能类似于try-finally,提供壹种上下文机制。要运用with语句的类,个中间必须提供多个放置函数__enter__和__exit__。前者在宗旨代码实施前执行,后者在大旨代码实践后实行。as后边的变量,是在__enter__函数中回到的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class echo():
    def output(self):
        print "hello world"
    def __enter__(self):
        print "enter"
        return self  #可以返回任何希望返回的东西
    def __exit__(self,exception_type,value,trackback):
        print "exit"
        if exception_type==ValueError:
            return True
        else:
            return Flase
  
>>>with echo as e:
    e.output()
     
输出:
enter
hello world
exit

完备的__exit__函数如下:

1
def __exit__(self,exc_type,exc_value,exc_tb)

其中,exc_type:格外类型;exc_value:异常值;exc_tb:格外追踪消息

当__exit__重返True时,异常不扩散

线程利器队列 queue

队列是1种数据结构,队列分为先进先出(FIFO) 和 先进后出(FILO)
Python Queue模块有两种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
三、还有一种是预先级队列等第越低越先出来。 class
queue.PriorityQueue(maxsize)
队列能够保险数据安全,是因为队列的内部维护着1把锁。每种去队列中取数据的都会保险数据的来宾。而列表纵然持有一样的效果,可是列表不是多少安全的

3、contextlib模块  

contextlib模块的法力是提供更易用的上下文管理器,它是由此Generator落成的。contextlib中的contextmanager作为装饰器来提供1种针对函数级其余上下文管理机制,常用框架如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from contextlib import contextmanager
@contextmanager
def make_context():
    print 'enter'
    try:
        yield "ok"
    except RuntimeError,err:
        print 'error',err
    finally:
        print 'exit'
         
>>>with make_context() as value:
    print value
     
输出为:
    enter
    ok
    exit

其间,yield写入try-finally中是为着保障充足安全(能处理万分)as后的变量的值是由yield重回。yield前边的语句可看作代码块实践前操作,yield之后的操作能够当作在__exit__函数中的操作。

以线程锁为例:

金沙注册送58 66

@contextlib.contextmanager
def loudLock():
    print 'Locking'
    lock.acquire()
    yield
    print 'Releasing'
    lock.release()

with loudLock():
    print 'Lock is locked: %s' % lock.locked()
    print 'Doing something that needs locking'

#Output:
#Locking
#Lock is locked: True
#Doing something that needs locking
#Releasing

金沙注册送58 67

成立叁个行列

Queue.Queue类正是2个队列的同台完成。队列长度可为Infiniti也许轻松。可因此Queue的构造函数的可选参数maxsize来设定队列长度。如若maxsize小于一就表示队列长度Infiniti。

4、contextlib.nested:减弱嵌套

对于:

1
2
3
with open(filename,mode) as reader:
    with open(filename1,mode1) as writer:
        writer.write(reader.read())

能够经过contextlib.nested举行简化:

1
2
with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer):
    writer.write(reader.read())

在python 二.7及事后,被1种新的语法替代:

1
2
with open(filename,mode) as reader,open(filename1,mode1) as writer:
    writer.write(reader.read())

向队列中插入数据

  • q.put(item,block)
    调用队列对象的put()方法在队尾插入1个门类。put()有七个参数,第二个item为要求的,为插入项目标值;第三个block为可选参数,默感到一。如若队列当前为空且block为1,put()方法就使调用线程暂停,直到空出贰个数码单元。假若block为0,put方法将抓住Full极度。

5、contextlib.closing() 

file类直接协理上下文管理器API,但稍事代表展开句柄的目的并不扶助,如urllib.urlopen()再次来到的目的。还有个别遗留类,使用close()方法而不帮忙上下文管理器API。为了保障关闭句柄,必要利用closing()为它创立一个上下文管理器(调用类的close方法)。

金沙注册送58 68

金沙注册送58 69

import contextlib
class myclass():
    def __init__(self):
        print '__init__'
    def close(self):
        print 'close()'

with contextlib.closing(myclass()):
    print 'ok'

输出:
__init__
ok
close()

金沙注册送58 70

从队列中抽取数据

  • q.get()
    调用队列对象的get()方法从队头删除并重临一个门类。可选参数为block,默认为True。若是队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如若队列为空且block为False,队列将引发Empty十分。

10 自定义线程池

简短版本:

金沙注册送58 71

金沙注册送58 72

import queue
import threading
import time

class ThreadPool(object):

    def __init__(self, max_num=20):
        self.queue = queue.Queue(max_num)
        for i in range(max_num):
            self.queue.put(threading.Thread)

    def get_thread(self):
        return self.queue.get()

    def add_thread(self):
        self.queue.put(threading.Thread)


'''
pool = ThreadPool(10)

def func(arg, p):
    print(arg)
    time.sleep(1)
    p.add_thread()


for i in range(30):
    Pool = pool.get_thread()
    t = Pool(target=func, args=(i, pool))
    t.start()
'''

金沙注册送58 73

复杂版本:

金沙注册送58 74

金沙注册送58 75

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import queue
import threading
import contextlib
import time

StopEvent = object()

class ThreadPool(object):

    def __init__(self, max_num, max_task_num = None):
        if max_task_num:
            self.q = queue.Queue(max_task_num)
        else:
            self.q = queue.Queue()
        self.max_num = max_num
        self.cancel = False
        self.terminal = False
        self.generate_list = []
        self.free_list = []

    def run(self, func, args, callback=None):
        """
        线程池执行一个任务
        :param func: 任务函数
        :param args: 任务函数所需参数
        :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
        :return: 如果线程池已经终止,则返回True否则None
        """
        if self.cancel:
            return
        if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
            self.generate_thread()
        w = (func, args, callback,)#主线程
        self.q.put(w)#主线程

    def generate_thread(self):
        """
        创建一个线程
        """
        t = threading.Thread(target=self.call)
        t.start()

    def call(self):
        """
        循环去获取任务函数并执行任务函数
        """
        current_thread = threading.currentThread()
        self.generate_list.append(current_thread)

        event = self.q.get()#if q为空,则阻塞住,一直等到有任务进来并把它取出来
        while event != StopEvent:

            func, arguments, callback = event
            try:
                result = func(*arguments)
                success = True
            except Exception as e:
                success = False
                result = None

            if callback is not None:
                try:
                    callback(success, result)
                except Exception as e:
                    pass

            with self.worker_state(self.free_list, current_thread):
                if self.terminal:
                    event = StopEvent
                else:
                    event = self.q.get()#key:该线程在这里继续等待新的任务,任务来了,继续执行
                                        #暂时将该线程对象放到free_list中。
        else:

            self.generate_list.remove(current_thread)

    def close(self):
        """
        执行完所有的任务后,所有线程停止
        """
        self.cancel = True
        full_size = len(self.generate_list)
        while full_size:
            self.q.put(StopEvent)
            full_size -= 1

    def terminate(self):
        """
        无论是否还有任务,终止线程
        """
        self.terminal = True

        while self.generate_list:
            self.q.put(StopEvent)

        self.q.queue.clear()

    @contextlib.contextmanager
    def worker_state(self, free_list, worker_thread):
        """
        用于记录线程中正在等待的线程数
        """
        free_list.append(worker_thread)#新的任务来的时候判断
                                 # if len(self.free_list) == 0 and len(self.generate_list) < self.max_num
                                 # 任务得创建新的线程来处理;如果len(self.free_list) != 0:由阻塞着的存在free_list中的线程处理(event = self.q.get())
        try:
            yield
        finally:
            free_list.remove(worker_thread)

# How to use


pool = ThreadPool(5)

def callback(status, result):
    # status, execute action status
    # result, execute action return value
    pass


def action(i):
    time.sleep(1)
    print(i)

for i in range(30):
    ret = pool.run(action, (i,), callback)

time.sleep(2)
print(len(pool.generate_list), len(pool.free_list))
print(len(pool.generate_list), len(pool.free_list))

# pool.close()
# pool.terminate()

金沙注册送58 76

 延伸:

金沙注册送58 77

金沙注册送58 78

import contextlib
import socket
@contextlib.contextmanager
def context_socket(host,port):
    sk=socket.socket()
    sk.bind((host,port))
    sk.listen(5)
    try:
        yield sk
    finally:sk.close()

with context_socket('127.0.0.1',8888) as socket:
    print(socket)

金沙注册送58 79

 

API

  • q.qsize() 再次回到队列的大大小小
  • q.empty() 假若队列为空,再次回到True,反之False
  • q.full() 假设队列满了,再次回到True,反之False
  • q.full 与 maxsize 大小对应
  • q.get([block[, timeout]]) 获取队列,timeout等待时间
  • q.get_nowait() 相当q.get(False)
    非阻塞 q.put(item) 写入队列,timeout等待时间
  • q.put_nowait(item) 相当q.put(item, False)
  • q.task_done() 在做到1项专门的学问现在,q.task_done()
    函数向任务已经到位的行列发送3个非能量信号
  • q.join() 实际上意味着等到队列为空,再进行别的操作

相关文章

网站地图xml地图