【美高梅开户网址】洗礼灵魂,_进度与线程中的lock

线程(下)

线程的概念

线程是操作系统能够举行演算调解的蝇头单位。它被含有在进程中。是进程中的实际运作单位。一条线程指的是进程中贰个纯净顺序的调节流。一个经过中得以并发两个线程,每条线程并行试行不一样的任务
四个线程的实施会由此线程的调解去抢占CPU的能源

线程与经过

1、同步锁 (Lock)

  当全局财富(counter)被攻下的情状,难题时有产生的案由就算从未决定八个线程对相同能源的拜会,对数据形成破坏,使得线程运转的结果不可预料。那种情状叫做“线程不安全”。在支付进度中大家亟要求防止这种情景,那怎么幸免?那就用到了互斥锁了。

例如:

 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为100的变为0

 

结果:

 

美高梅开户网址 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)

  

并未异常的大的转移对吗,只是加了2个一时半刻变量,并且中途抛锚了0.2s而已。

而以此结果就不雷同了:

美高梅开户网址 2

 

此间自个儿先说下,time.sleep(0.二)是自己故意加的,正是要反映这一个功效,借使你的计算机不加sleep就早已面世那几个状态了那么您就无须加了,那咋回事呢?那正是线程共用多少的神秘危急性,因为线程都以抢着CPU能源在运行,只要发觉有空儿就分别抢着跑,所以在那停顿的0.2s时间中,就会有新的线程抢到机会初阶运维,那么玖拾四个线程就有九十多个线程在抢机会运营,抢到的时刻都以在temp还并没有减一的值,也等于100,所以超过半数的线程都抢到了十0,然后减1,少一些线程没抢到,抢到已经减了贰次的99,这正是干什么会是9九的缘由。而以此抢占的年华和结果并不是根本的来由,究其根本照旧因为计算机的配备难点了,配置越好的话,那种越不便于生出,因为四个线程抢到CPU能源后直接在运营,别的的线程在短短的刻钟里得不到机会。

 

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

 

图解: 

美高梅开户网址 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)

  

运作结果:

美高梅开户网址 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)

 捌.死锁现象/可接纳锁

前面既然已经用了1块锁,那么相信在后头的支付中,相对会用到使用多少个同步锁的时候,所以那边模拟一下采纳七个一齐锁,看看会有啥样情况时有产生

 

#!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()

 

  

运作结果:

美高梅开户网址 5

 

那边就直接阻塞住了,因为demo一函数用的锁是外围a锁,内层b锁,demo2函数刚好相反,外层b锁,内层a锁,所以当八线程运维时,八个函数同时在互抢锁,何人也不让何人,那就导致了堵截,这一个阻塞现象又叫死锁现象。

 

那么为了避免发生那种事,大家得以行使threading模块下的XC60LOCK来创建重用锁依此来防止那种情景

 

#!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()

  

运作结果:

美高梅开户网址 6

 

其1奥迪Q7lock其实正是Lock+总括器,总结器里的起始值为0,每嵌套1层锁,计算器值加壹,每释放一层锁,总计器值减一,和协助举行锁同样,唯有当班值日为0时才算了却,让别的线程接着抢着运营。而以此汉兰达lock也有3个官方一点的名字,递归锁

 

 那么估摸有朋友会问了,为何会有死锁现象吧?恐怕您应有问,是如何生产意况导致有死锁现象的,仍旧那句,为了维护数量同步性,防止二10多线程操作同1数据时爆发争辩。这一个说辞很笼统对啊,作者说细点。比方前面的购物车系统,纵然大家在操作数据时又再度取了贰遍数据来保证数据的真实性,借使三个用户同时登入购物车系统在操作的话,也许分歧的操作但会波及到同贰个数目标时候,就会促成数据只怕分裂步了,那么就足以在中间代码里加贰回联袂锁,然后再在骨子里操作处再加1次联合锁,那样就应运而生多层同步锁,那么也就会并发死锁现象了,而此时那几个死锁现象是我们开采中恰恰需求的。

本人想,说了这些例子你应当能够领悟为何lock里还要有lock,很轻巧产生死锁现象大家依旧要用它了,简单的讲假设须求死锁现象就用联合锁,不须要就换到递归锁。

 

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个线程锁

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()

  

运转结果:

美高梅开户网址 7

 

即便您亲自测试那段代码,你会意识,那些结果是二个壹组出的,出了1回3个1组的,最终出了1个1组,一个一组都是互相的,中间停顿二秒。

那里能够给很形象的例子,如若有些地点的停车位只好同时停三辆车,当停车位有空时别的的车才足以停进来。那里的二个停车位就一定于非确定性信号量。

 

2)BoundedSemaphore

既是有随机信号量为大家做到这一个壹组1组的操作结果,但敢不敢保险这几个线程就不会突然的越出这么些设定好的车位呢?例如设定好的三个时域信号量一组,大家都晓得线程是争强着运营,万一就有除了设定的二个线程外的一七个线程抢到了运行权,什么人也不让何人,正是要协同运转吧?好比,那里唯有二个车位,已经停满了,但有人正是要去挤一挤,出现第4辆或然第5辆车的情形,这一个和现实生活中的例子简直太适宜了对啊?

那么大家怎么办?当然这些标题早已有人想好了,所以有了时限信号量的升级版——绑定式复信号量(Bounded塞马phore)。既然是升格版,那么同时域信号量同样该片段都有个别,用法也一样,正是有个成效,在设定好的多少个线程一组运转时,假如有别的线程也抢到运转权,那么就会报错

比如thread_lock =
threading.BoundedSemaphore(5),那么十贰线程同时运维的线程数就不能够不在5以内(包涵伍),不然就报错。换句话,它有着了实时监察和控制的作用,好比停车位上的保卫安全,假诺开掘车位满了,就禁止放行车辆,直到有空位了再允许车辆进入停车。

因为这么些很简短,就多了个监督效果,别的和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中为了补助在同一线程中多次请求同一财富,python提供了可重入锁大切诺基Lock。那个奥迪Q三Lock内部维护着三个Lock和多少个counter变量,counter记录了acquire的次数,从而使得能源能够被一再require。直到三个线程全体的acquire都被release,其余的线程才具赢得能源。上面包车型大巴例证假如利用SportageLock替代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()

  

十.标准变量同步锁

不多说,它也是3个线程锁,本质上是在Tiguanlock基础之上再增多上边包车型地铁四个办法 

condition = threading.Condition([Lock/RLock]),私下认可里面包车型客车参数是Enclavelock

 

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

notify():条件创制后调用,文告等待池激活1个线程

【美高梅开户网址】洗礼灵魂,_进度与线程中的lock。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()

  

运作结果:

美高梅开户网址 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管理二个放权的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+一;
计数器不可能小于0;当计数器为0时,acquire()将封堵线程直到其余线程调用release()。

实例:(同时唯有5个线程能够获得semaphore,即能够界定最阿比让接数为5):

 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()

  

 

运行结果:

美高梅开户网址 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对象的评释为假,那么这么些线程将会被直接不通直至该标识为真。一个线程如若将三个伊夫nt对象的确定性信号标识设置为真,它将唤起全数等待这一个伊芙nt对象的线程。纵然一个线程等待多个已经被安装为实在伊夫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解释器加了壹把大锁。大家通晓Python是由解释器执行的,由于GIL的留存
只可以有3个线程被解释器实行,那样就使得Python在四线程推行上的频率变低。由于历史遗留难题,开采大批量库代码开垦者现已重度注重GIL而卓殊麻烦去除了。相当于说在多核CPU上,并行奉行的Python10贰线程,乃至比不上串行实践的Python程序,那就是GIL存在的主题材料

1 线程的二种调用方式

直接调用

实例1:

美高梅开户网址 10

美高梅开户网址 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())

美高梅开户网址 12

承袭式调用:

美高梅开户网址 13

美高梅开户网址 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()

美高梅开户网址 15

4、队列(queue)

”’

创办三个“队列”对象

import queueq
q = queue.Queue(maxsize = 10)
    #queue.Queue类便是1个行列的一道实现。队列长度可为Infiniti恐怕简单。可透过Queue的构造函数的可选参数
    #maxsize来设定队列长度。假若maxsize小于1就代表队列长度无限。

q.put()    将3个值2贰放入队列中

    #调用队列对象的put()方法在队尾插入2个品类。put()有多个参数,第多少个item为须要的,为插入项目的值;第一个block为可选参数,默认为一。如果队列当前为空且block为壹,put()方法就使调用线程暂停,直到空出多个数目单元。若是block为0,put方法将引发Full至极。

q.get()    将二个值从队列中抽出    

    #调用队列对象的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)

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

 

1)创设三个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类正是3个行列的1块儿完结。队列长度可为Infiniti可能轻松。可由此Queue的构造函数的可选参数maxsize来设定队列长度。如若maxsize小于一就表示队列长度Infiniti。

二)将1个值放入队列中
q.put(obj)
调用队列对象的put()方法在队尾插入一个系列。put()有三个参数,第一个item为要求的,为插入项目的值;第三个block为可选参数,默以为
一。假若队列当前为空且block为1,put()方法就使调用线程暂停,直到空出二个数据单元。假如block为0,put方法将吸引Full非凡。

叁)将二个值从队列中抽出
q.get()
调用队列对象的get()方法从队头删除并赶回四个体系。可选参数为block,默以为True。假诺队列为空且block为True,get()就使调用线程暂停,直至有品种可用。假诺队列为空且block为False,队列将引发Empty分外。

 

例:

美高梅开户网址 16

 

 

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

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

 

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

美高梅开户网址 17

 

 

5)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():实际上意味着等到队列为空,再实施别的操作

 

陆)队列有如何便宜,与列表差别

队列自个儿就有一把锁,内部已经保持一把锁,借使您用列表的话,当条件是在十2线程下,那么列表数据就必将会有争辩,而队列不会,因为此,队列有个绰号——八线程利器

例:

#!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()

  

运转结果:

美高梅开户网址 18

 

此处素有毫无加锁就成功了前面包车型大巴劳动者消费者模型,因为queue里面自带了1把锁。

 

好的,关于线程的知识点,讲明完。

 

Python GIL的面世气象

在Python中只要职分是IO密集型的,能够行使二十八线程。而且Python的八线程十分擅长管理那种主题材料
而要是Python中只要任务是持筹握算密集型的,就供给处理一下GIL

二 Join & Daemon

美高梅开户网址 19

美高梅开户网址 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())

美高梅开户网址 21

setDaemon(True):

      将线程注脚为护理线程,必须在start() 方法调用此前设置,
假若不设置为守护线程程序会被无限挂起。这几个措施基本和join是倒转的。当大家在程序运营中,施行八个主线程,借使主线程更创办贰个子线程,主线程和子线程
就分兵两路,分别运转,那么当主线程达成想脱离时,会核实子线程是还是不是实现。如若子线程未到位,则主线程会等待子线程达成后再脱离。可是有时大家要求的是
只要主线程实现了,不管子线程是不是产生,都要和主线程一同退出,那时就足以
用setDaemon方法啦 

join():

       在子线程实现运维在此之前,那些子线程的父线程将直接被卡住。

别的方法

美高梅开户网址 22

美高梅开户网址 23

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

美高梅开户网址 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!")
'''

四线程式爬虫

局地朋友学完线程还不领会线程到底能运用于如何生活其实,好的,不多说,来,大家爬下堆糖网()的校花照片。

 

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('校花')

  

运转结果:

美高梅开户网址 25

 

在与本py文件一律的目录下,有个duitangpic的文本夹,展开看看:

美高梅开户网址 26

 

 全是靓妹,而且不出意外又好几千张呢,笔者那只有1000多张是因为作者手动甘休了py程序运维,毕竟自身那是出现说法,不要求真正等程序运转完。小编差不多估量,不出意外应该能爬到两千张左右的肖像

 

什么样,老铁,得劲不?刺不激情?感受到102线程的用途了不?而且那要么python下的伪10贰线程(IO密集型,但并不到底真正意义上的十二线程),你用任何的言语来爬更换感。

 

join 和daemon

join

  • 在子线程达成运营从前,这么些子线程的父线程将向来被打断。在1个先后中我们实践二个主线程,这一个主线程再创建一个子线程,主线程和子线程就互相实行,当子线程在主线程中调用join方法时,主线程会等待子线程推行完后再截至

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

daemon

  • setDaemon(true)
    将线程注解为料理线程,必须在start() 方法调用此前安装,
    假使不安装为护理线程程序会被Infiniti挂起。这一个方式基本和join是相反的。当咱们在程序运转中,实践3个主线程,如若主线程更创制3个子线程,主线程和子线程
    就分兵两路,分别运转,那么当主线程落成想退出时,会核查子线程是不是到位。固然子线程未形成,则主线程会等待子线程实现后再脱离。可是有时我们须要的是
    只要主线程达成了,不管敬仲线程是还是不是落成,都要和主线程一齐退出,那时就能够用setDaemon方法啦
  • currentThread() 获取当前举行的线程

三 同步锁(Lock)

美高梅开户网址 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 )

美高梅开户网址 28

 

 

美高梅开户网址 29

 

注意:

①:  why num-=一没难题啊?那是因为动作太快(完结这么些动作在切换的时光内)

二: if
sleep(一),现象会越来越强烈,9二十一个线程各个毫无疑问都没有实行完就开始展览了切换,大家说过sleep就等效于IO阻塞,一s以内不会再切换回来,所以最终的结果自然是9玖.

 

三个线程都在同时操作同多少个共享能源,所以变成了财富破坏,如何是好吧?

有同学会想用join呗,但join会把全部线程给停住,产生了串行,失去了二十四线程的含义,而作者辈只必要把计算(涉及到操作公共数据)的时候串行推行。

咱俩得以由此联合锁来消除那种主题素材

美高梅开户网址 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 )

美高梅开户网址 31

主题素材解决,但

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

Python的线程在GIL的主宰之下,线程之间,对1切python解释器,对python提供的C
API的造访都以排斥的,那足以看成是Python内核级的排斥机制。可是这种互斥是大家无法决定的,大家还要求另外一种可控的排挤机制———用户级互斥。内核级通过互斥珍爱了基础的共享财富,同样,用户级互斥爱抚了用户程序中的共享能源。

GIL
的职能是:对于两个解释器,只可以有3个thread在实施bytecode。所以每时每刻唯有一条bytecode在被推行3个thread。GIL保障了bytecode
那层面上是thread safe的。
而是假设您有个操作比方 x +=
壹,这些操作须要多少个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

4 线程死锁和递归锁

     
在线程间共享多少个能源的时候,若是多个线程分别占领1部分能源并且同时等待对方的财富,就会导致死锁,因为系统决断那有个别能源都正在利用,全体那三个线程在无外力功能下将直接等候下去。上面是二个死锁的例证:

美高梅开户网址 32

美高梅开户网址 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()#等待线程结束,后面再讲。

美高梅开户网址 34

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

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

为了援助在同1线程中再叁呼吁同一能源,python提供了“可重入锁”:threading.牧马人Lock。BMWX3Lock内部维护着二个Lock和一个counter变量,counter记录了acquire的次数,从而使得能源可以被数次acquire。直到3个线程全数的acquire都被release,其余的线程才具博得能源。

应用

美高梅开户网址 35

美高梅开户网址 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)

美高梅开户网址 37

队列的选拔:生产者消费者模型

  在线程世界里,生产者正是生产数据的线程,消费者正是消费数量的线程。在10贰线程开荒个中,若是劳动者管理速度比较快,而消费者管理速度一点也不快,那么生产者就务须等待顾客管理完,才具延续生产数据。一样的道理,借使买主的拍卖才具当先生产者,那么消费者就不可能不等待生产者。为了消除那几个主题材料于是引进了劳动者和买主形式。

  生产者消费者方式是经过一个容器来解决劳动者和买主的强耦合难题。劳动者和顾客相互之间不直接通信,而经过阻塞队列来实行电视发表,所以生产者生产完数据之后不要等待顾客管理,直接扔给卡住队列,消费者不找生产者要多少,而是径直从绿灯队列里取,堵塞队列就一定于一个缓冲区,平衡了劳动者和消费者的拍卖能力。

  那就好像,在餐厅,厨子做好菜,不要求平昔和客户调换,而是交由前台,而客户去饭菜也不须要不找厨子,直接去前台领取就可以,那也是1个结耦的经过。

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()

  

  

 

分析

下边的先后中,咱们想要的是展开九21个线程,各个线程将共享数据减去壹,不过大家开采输出的结果是9九,这种状态是因为二十四线程在cpu中施行时是抢占式的,程序在上马实行时,开启了一百个线程去实践,当程序施行到time.sleep(0.一)时,由于爆发了线程的围堵,所以cpu进行了切换,此时,程序的共享变量num是十0,中间变量tmp也是100
在线程阻塞过后,将共享变量num的值减一,值变为9九此时别的的线程获得cpu的实行机会,而当前线程中的共享变量num的值依旧十0所以试行减1操作后,又将中间值赋值给共享变量num所以num的值从来为9玖

  • 线程的实施情状
![](https://upload-images.jianshu.io/upload_images/6052465-461749d8c9eb7ea5.png)

多线程抢占.png

5 条件变量同步(Condition)

     
有一类线程要求满足条件之后工夫够继续推行,Python提供了threading.Condition
对象用于规范变量线程的支撑,它除了能提供奇骏Lock()或Lock()的章程外,还提供了
wait()、notify()、notifyAll()方法。

      lock_con=threading.Condition([Lock/Rlock]):
锁是可选选项,不传人锁,对象活动创造三个奇骏Lock()。

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

实例

美高梅开户网址 38

美高梅开户网址 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()

美高梅开户网址 40

Python 同步锁

操作锁的办法在threading 模块中 Lock()

  • threading.Lock() 会得到1把锁
  • 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))

6 同步条件(伊夫nt)

     
条件同步和规范变量同步大约意思,只是少了锁作用,因为条件同步设计于不访问共享能源的标准碰着。event=threading.伊芙nt():条件遭逢目的,起初值
为False;

美高梅开户网址 41

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

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

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

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

美高梅开户网址 42

实例1:

美高梅开户网址 43

美高梅开户网址 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()

美高梅开户网址 45

实例2:

美高梅开户网址 46

美高梅开户网址 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()

美高梅开户网址 48

线程中的死锁和递归锁

在线程间共享四个能源的时候,假诺多个线程分别攻下1部分能源并且还要等待对方释放对方的财富,就会促成死锁,因为系统决断那有的能源正在选取,所以那三个线程在无外力功能下将直接等候下去
看个栗子:

'''
线程死锁
'''

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)

     
确定性信号量用来决定线程并发数的,BoundedSemaphore或Semaphore管理多少个放到的计数
器,每当调用acquire()时-一,调用release()时+壹。

      计数器无法小于0,当计数器为
0时,acquire()将卡住线程至三头锁定状态,直到别的线程调用release()。(类似于停车位的概念)

     
BoundedSemaphore与Semaphore的绝无仅有差距在于前者将要调用release()时检查计数
器的值是不是超越了计数器的启幕值,假诺超过了将抛出二个百般。

实例:

美高梅开户网址 49

美高梅开户网址 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()

美高梅开户网址 51

化解死锁的情势

  • threading.OdysseyLock() 可重入锁
    为了援救在同1线程中多次请求同1能源,python提供了“可重入锁”:threading.汉兰达Lock。CR-VLock内部维护着三个Lock和1个counter变量,counter记录了acquire的次数,从而使得财富得以被多次acquire。直到1个线程全部的acquire都被release,别的的线程才能取得财富。可重入锁的中间维持了一个计数器和锁对象。

 八 多线程利器(queue)

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

信号量

能量信号量用来支配线程并发数的,BoundedSemaphore或Semaphore管理八个停放的计数器,每当调用acquire()时-1,调用release()时+一
计数器不可能小于0当计数器为0时,acquire()将阻塞线程至二只锁定状态,直到别的线程调用release()。
Bounded塞马phore与Semaphore的绝无仅有差别在于前者将要调用release()时检查计数器的值是还是不是超越了计数器的初始值。如若超过了将抛出贰个可怜

queue列队类的法子

美高梅开户网址 52

创建贰个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类就是贰个行列的联合达成。队列长度可为Infiniti也许个别。可透过Queue的构造函数的可选参数maxsize来设定队列长度。假诺maxsize小于一就表示队列长度Infiniti。

将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入多个档期的顺序。put()有多个参数,第1个item为须要的,为插入项目标值;第三个block为可选参数,默感到
一。假如队列当前为空且block为一,put()方法就使调用线程暂停,直到空出二个数码单元。假诺block为0,put方法将引发Full至极。

将一个值从队列中抽出
q.get()
调用队列对象的get()方法从队头删除并赶回二个品种。可选参数为block,默感觉True。假诺队列为空且block为True,get()就使调用线程暂停,直至有项目可用。假如队列为空且block为False,队列将引发Empty非凡。

Python Queue模块有二种队列及构造函数:
一、Python Queue模块的FIFO队列先进先出。  class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。             class
queue.LifoQueue(maxsize)
3、还有1种是预先级队列等级越低越先出来。   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() 实际上意味着等到队列为空,再推行别的操作

美高梅开户网址 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:

美高梅开户网址 54

美高梅开户网址 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()

美高梅开户网址 56

实例2:

美高梅开户网址 57

美高梅开户网址 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()

美高梅开户网址 59

实例3:

美高梅开户网址 60

美高梅开户网址 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()

美高梅开户网址 62

瞩目:列表是线程不安全的

美高梅开户网址 63

美高梅开户网址 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()

美高梅开户网址 65

规格变量同步

有1类线程须要知足条件之后本事够继续实施,Python提供了threading.Condition
对象用于标准变量线程的支撑,它除了能提供安德拉Lock()或Lock()的方式外,还提供了
wait()、notify()、notifyAll()方法。
规则变量也是线程中的壹把锁,可是规格变量能够兑现线程间的通讯,类似于Java中的唤醒和等候

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

上下文物管理理器的天职是:代码块实践前打算,代码块实行后处置

创建标准变量锁

  • lock_con = threading.Condition(Lock/福特Explorerlock)
    锁是可选选项,不扩散锁对象活动创设2个TiguanLock()
  • wait() 条件不满足时调用,线程会释放锁并跻身等待绿灯
  • notify() 条件创立后调用,文告等待池激活三个线程
  • 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()

一、怎么样行使上下文管理器:

什么样张开2个文件,并写入”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,提供1种上下文机制。要选取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

队列是一种数据结构,队列分为先进先出(FIFO) 和 先进后出(FILO)
Python Queue模块有二种队列及构造函数:
一、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
贰、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有1种是事先级队列等级越低越先出来。 class
queue.PriorityQueue(maxsize)
队列能够保障数据安全,是因为队列的中间维护着1把锁。每种去队列中取数据的都会保障数据的平安。而列表纵然有着同等的机能,可是列表不是数码安全的

3、contextlib模块  

contextlib模块的职能是提供更易用的上下文处理器,它是经过Generator完毕的。contextlib中的contextmanager作为装饰器来提供一种针对函数品级的上下文管理机制,常用框架如下:

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__函数中的操作。

以线程锁为例:

美高梅开户网址 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

美高梅开户网址 67

始建叁个连串

Queue.Queue类正是3个系列的1块儿落成。队列长度可为Infiniti大概个别。可经过Queue的构造函数的可选参数maxsize来设定队列长度。尽管maxsize小于1就代表队列长度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 2.七及其后,被1种新的语法代替:

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

向队列中插入数据

  • q.put(item,block)
    调用队列对象的put()方法在队尾插入3个品类。put()有五个参数,第一个item为要求的,为插入项目的值;第3个block为可选参数,默以为一。假设队列当前为空且block为一,put()方法就使调用线程暂停,直到空出1个多少单元。假诺block为0,put方法将引发Full分外。

5、contextlib.closing() 

file类直接帮助上下文处理器API,但有些代表张开句柄的靶子并不协助,如urllib.urlopen()重返的对象。还某些遗留类,使用close()方法而不援救上下文管理器API。为了确定保障关闭句柄,供给采取closing()为它创制二个上下文管理器(调用类的close方法)。

美高梅开户网址 68

美高梅开户网址 69

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

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

输出:
__init__
ok
close()

美高梅开户网址 70

从队列中抽取数据

  • q.get()
    调用队列对象的get()方法从队头删除并回到叁个连串。可选参数为block,私下认可为True。如若队列为空且block为True,get()就使调用线程暂停,直至有品种可用。借使队列为空且block为False,队列将引发Empty分外。

10 自定义线程池

一句话来讲版本:

美高梅开户网址 71

美高梅开户网址 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()
'''

美高梅开户网址 73

复杂版本:

美高梅开户网址 74

美高梅开户网址 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()

美高梅开户网址 76

 延伸:

美高梅开户网址 77

美高梅开户网址 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)

美高梅开户网址 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() 在成功一项职业之后,q.task_done()
    函数向任务现已形成的队列发送2个能量信号
  • q.join() 实际上意味着等到队列为空,再试行别的操作

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图