设为首页 加入收藏

TOP

Python全栈开发之11、进程和线程(一)
2017-09-30 16:19:30 】 浏览:5890
Tags:Python 全栈 开发 进程 线程

一、线程

  多任务可以由多进程完成,也可以由一个进程内的多线程完成,一个进程内的所有线程,共享同一块内存python中创建线程比较简单,导入threading模块,下面来看一下代码中如何创建多线程。

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

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=f1, args=(i,))
        t.start()
    print('start')          # 主线程等待子线程完成,子线程并发执行


>>start
>>2
>>1
>>3
>>0
>>4

  主线程从上到下执行,创建5个子线程,打印出'start',然后等待子线程执行完结束,如果想让线程要一个个依次执行完,而不是并发操作,那么就要使用join方法。下面来看一下代码

import threading
import time

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

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=f1, args=(i,))
        t.start()
        t.join()
    print('start')      # 线程从上到下依次执行,最后打印出start

>>0
>>1
>>2
>>3
>>4
>>start

  上面的代码不适用join的话,主线程会默认等待子线程结束,才会结束,如果不想让主线程等待子线程的话,可以子线程启动之前设置将其设置为后台线程,如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止,前台线程则相反,若果不加指定的话,默认为前台线程,下面从代码来看一下,如何设置为后台线程。例如下面的例子,主线程直接打印start,执行完后就结束,而不会去等待子线程,子线程中的数据也就不会打印出来

import threading
import time

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

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=f1, args=(i,))
        t.setDaemon(True)
        t.start()

    print('start')      # 主线程不等待子线程

>> start 

  除此之外,自己还可以为线程自定义名字,通过 t = threading.Thread(target=f1, args=(i,), name='mythread{}'.format(i)) 中的name参数,除此之外,Thread还有一下一些方法

  • t.getName() : 获取线程的名称
  • t.setName() : 设置线程的名称 
  • t.name : 获取或设置线程的名称
  • t.is_alive() : 判断线程是否为激活状态
  • t.isAlive() :判断线程是否为激活状态
  • t.isDaemon() : 判断是否为守护线程

二、线程锁

  由于线程是共享同一份内存的,所以如果操作同一份数据,很容易造成冲突,这时候就可以为线程加上一个锁了,这里我们使用Rlock,而不使用Lock,因为Lock如果多次获取锁的时候会出错,而RLock允许在同一线程中被多次acquire,但是需要用n次的release才能真正释放所占用的琐,一个线程获取了锁在释放之前,其他线程只有等待。 

import threading
G = 1
lock = threading.RLock()
def fun():
    lock.acquire()    # 获取锁
    global G
    G += 2
    print(G, threading.current_thread().name)
    lock.release()   # 释放锁
    return


for i in range(10):
    t = threading.Thread(target=fun, name='t-{}'.format(i))
    t.start()

3 t-0
5 t-1
7 t-2
9 t-3
11 t-4
13 t-5
15 t-6
17 t-7
19 t-8
21 t-9    

三、线程间通信Event

Event是线程间通信最间的机制之一,主要用于主线程控制其他线程的执行,主要用过wait,clear,set,这三个方法来实现的的,下面来看一个简单的例子,

import threading
import time

def f1(event):
    print('start:')
    event.wait()            # 阻塞在,等待 set
    print('end:')

if __name__ == '__main__':
    event_obj  = threading.Event()
    for i in range(5):
        t = threading.Thread(target=f1, args=(event_obj,))
        t.start()

    event_obj.clear()      # 清除标志位 
    inp = input('>>>>:')
    if inp == 'true':
        event_obj.set()   # 设置标志位

四、队列  

  可以简单的理解为一种先进先出的数据结构,比如用于生产者消费者模型,或者用于写线程池,以及前面写select的时候,读写分离时候可用队列存储数据等等,以后用到队列的地方很多,因此对于队列的用法要熟练掌握。下面首先来看一下队列提供了哪些用法

q = queue.Queue(maxsize=0)  # 构造一个先进显出队列,maxsize指定队列长度,为0时,表示队列长度无限制。

q.join()        # 等到队列为kong的时候,在执行别的操作
q.qsize()       # 返回队列的大小 (不可靠)
q.empty()       # 当队列为空的时候,返回True 否则返回False (不可靠)
q.full()        # 当队列满的时候,返回True,否则返回False (不可靠)
q.put(item, block=True, timeout=None)   # 将item放入Queue尾部,item必须存在,参数block默认为True,表示当队列满时,会等待
                        # 为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示会阻塞设置的时间,
                        # 如果在阻塞时间里 队列还是无法放入,则引发 queue.Full 异常

q.get(block=True, timeout=None)     #  移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞
                       #  阻塞的话若此时队列为空,则引发queue.Empty异常。 可选参数timeout,表示会阻塞设置
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python按行读取文件 下一篇python技巧之下划线(二)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目