Python多线程

我想干点什么呢?有点目的性才有做下去的动力!


  • 多线程1

    据说这是一个最简单的多线程,也是找别人的看的,我真的不会使用帮助文档。据说还有一个thread,但是不推荐使用了,所以直接从threading入门

#coding=utf-8
import threading;
from time import sleep;

def music():
    for i in range(15):
        print('nusic--->',i);
        sleep(2);

def movie():
    for i in range(15):
        print('movie------->',i);
        sleep(3);

if __name__=='__main__':
    threads=[];#创建一个线程数组,存放创建的线程
    t1=threading.Thread(target=music);#创建第一个线程,如果target的函数有参数,以tuple形式作为第二个参数传入
    t2=threading.Thread(target=movie);#创建第二个线程
    threads.append(t1);#将创建的线程加入线程数组
    threads.append(t2);
    for t in threads:
        t.setDaemon(True);#setDaemon(True)将线程声明为守护线程,而且必须在star()方法前设置,如果不设置,我也不知道会怎样。。。
        t.start();#启动线程
        
    for t in threads:
        print(threading.currentThread());
        t.join();#如果没有这句,那么启动了线程后,就直接向下执行了,主线程并不会等待子线程结束再继续,而且主线程结束了,子线程也就over了。
    #print(threading.currentThread());
    print('all done ! ');

join()的主要作用就是在它非空时阻塞主线程(或者说阻塞子线程的父线程?)。貌似join()中只能容下一个线程,当把print(threading.currentThread());放在下面时,只输出一次结果,这是正确的。当放在上面一点时,会在第一个次for循环输出一次,待第一个被join()的子线程结束时输出第二次,哦,好像就应该这样啊,现在外面是主线程,它阻塞了主线程他肯定要等第一个执行完才会继续,开来猜测完全正确。


  • 多线程2

继承自threading.Thread拥有自己的可自定义线程类
.共享数据,线程同步
数据共享。当多个线程都要去修改某一个共享数据的时候,我们需要对数据访问进行同步。


  1. Rlock,实现同步
#coding=utf-8

import threading;
from time import sleep;
class myThreading(threading.Thread):#继承threading.Thread
    num=0;
    myLock=threading.RLock();

    def __init__(self,name,sleepSec):
        threading.Thread.__init__(self);#父类初始化
        self.__name=name;
        self.__sleepSec=sleepSec;
    def run(self):#__init__和run是必须重写的
        while(True):
            self.__class__.myLock.acquire();#获得锁,成功获得锁定后返回True。我们把修改共享数据的代码成为“临界区”。必须将所有“临界区”都封闭在同一个锁对象的acquire和release之间。
            print('%s acquire+ the lock, num= %d'%(self.__name,self.__class__.num));
            if(self.__class__.num >= 4):
                self.__class__.myLock.release();
                print('%s release- the lock for bigger than, num= %d'%(self.__name,self.__class__.num));
                break;
            self.__class__.num +=1;
            print('%s release- the lock, num= %d'%(self.__name,self.__class__.num));
            self.__class__.myLock.release();
            sleep(self.__sleepSec);

if __name__=='__main__':
    t1=myThreading("t1",5);
    t2=myThreading("t2",2);
    t1.setDaemon(True);
    t2.setDaemon(True);
    t1.start();
    t2.start();
    t1.join();
    t2.join();
输出
t1 acquire+ the lock, num= 0
t1 release- the lock, num= 1
t2 acquire+ the lock, num= 1
t2 release- the lock, num= 2
t2 acquire+ the lock, num= 2
t2 release- the lock, num= 3
t2 acquire+ the lock, num= 3
t2 release- the lock, num= 4
t1 acquire+ the lock, num= 4
t1 release- the lock for bigger than, num= 4
t2 acquire+ the lock, num= 4
t2 release- the lock for bigger than, num= 4

2.条件同步
所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。 它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。Condition的价值在于其提供的wait和notify的语义

#coding=utf-8

import threading;

num=0;
con=threading.Condition();#条件变量

class Producer(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self);
        self.__name=name;
    
    def run(self):
        global num;
        con.acquire();#取得条件变量
        if(num>0):
            con.wait();#有足够的产品,就可以停下来等待,也就是释放资源了
        else:
            for i in range(5):
                num +=2;
                print('producer>>>>>>%d'%num);
            con.notify();#发出消息,我准备好了,释放资源了,可以来用了
        print('producer done !');
        con.release();#彻底释放了

class Consumer(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self);
    def run(self):
        global num;
        con.acquire();#取得条件变量
        if(num==0):
            print('consumer waiting......');
            con.wait();#没有产品,等待生产,
        else:
            for i in range(5):
                num-=1;
                print('consuming......{num}');
            con.notify();#发出通知,没货了,快生产
        print('consumer done !');
        con.release();

if __name__=='__main__':
    print('start Consumer');
    c=Consumer('consumer');
    print('start Producer');
    p=Producer('producer');

    c.setDaemon(True);
    p.setDaemon(True);
    c.start();
    p.start();
    c.join();
    p.join();
 #抱歉,上面那个不对,这个才可以运行。主要在于上面误读了notify(),它只是发出通知,并没有释放资源的作用,
 #所以,notify之后还要release其他线程才能操作共享资源。
#coding=utf-8

import threading;
import time;

class Goods:
    def __init__(self):
        self.__num=0;
    def add(self):
        self.__num+=2;
    def sub(self):
        self.__num-=1;
    def get(self):
        return self.__num;
    def empty(self):
        if(self.__num > 0):
            return False;
        else:
            return True;

class Producer(threading.Thread):
    def __init__(self,name,con,num):
        threading.Thread.__init__(self);
        self.__name=name;
        self.__con=con;
        self.__goods=num;
        print('creat Producer\n');
        

    def run(self):
        print('start Producer\n');
        con=self.__con;
        goods=self.__goods;
        while(True):
            con.acquire();#取得条件变量
            if(not goods.empty()):
                con.wait();#有足够的产品,就可以停下来等待,也就是释放资源了
            else:
                goods.add();
                print('producer>>>>>>%d'%goods.get());
                con.notify();#发出消息,我准备好了,释放资源了,可以来用了
                print('producer done !');
            con.release();#彻底释放了
            time.sleep(2);

class Consumer(threading.Thread):
    def __init__(self,name,con,num):
        threading.Thread.__init__(self);
        self.__name=name;
        self.__con=con;
        self.__goods=num;
        print('create Consumer');

    def run(self):
        print('start Consumer');
        con=self.__con;
        goods=self.__goods;
        while(True):
            con.acquire();#取得条件变量
            if(goods.empty()):
                print('consumer waiting......');
                con.wait();#没有产品,等待生产,
            else:
                goods.sub();
                print('consuming......%d'%goods.get());   
                con.notify();#发出通知,没货了,快生产
                print('consumer done !');
            con.release();
            time.sleep(5); 




if __name__=='__main__':
    con=threading.Condition();#条件变量
    goods=Goods();
    c=Consumer('consumer',con,goods);
    p=Producer('producer',con,goods);
    c.setDaemon(True);
    p.setDaemon(True);
    c.start();
    p.start();
    c.join();
    p.join();

3.queue
简单的理解为,生产者(多个)进程向queue的一段装入数据,消费者(多个)进程从另一端取数据,并不是用queue控制进程仅是数据交换的容器

Queue.task_done() 
在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号,
主要是关系到Queue.join()阻塞着主进程,当queue空时才会继续
Queue.join() 实际上意味着等到队列为空,再执行别的操作。看来也是一定程度上有些控制了进程。
#coding=utf-8

import queue
import threading
import time

class threadingQueue(threading.Thread):
    def __init__(self,name,q):
        threading.Thread.__init__(self);
        self.name=name;
        self.q=q;
    def run(self):
        while(True):
            #time.sleep(5);
            #print("%s threading start \n"%self.name);
            a=self.q.get();
            print('------',a,'-----\n');
            self.q.task_done();
            

if __name__=='__main__':
    data=[1,2,3,4,5,6,7,8,9,0];
    qTmp=queue.Queue();
    for i in data:
        qTmp.put(i);
    for j in range(3):
        t=threadingQueue(str(j),qTmp);
        t.setDaemon(True);
        t.start();
    qTmp.join();
    print('All Done !');
#最后的输出都是都是按照队列的顺序来的,没有被破坏,
#但是有趣的是线程间有打断,print时出现交叉
#也可以看出,一个进程负责添加一个进程提出数据也是可以的,
#但是,如果初始queue为空,怎么保证不会出现主进程直接到queue.join()这步直接退出?

3.信号量
信号量维护着一个计数器,指定可同时访问资源或者进入临界区的线程数。信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,其他线程就停止访问信号量,直到另一个线程释放信号量。


#coding=utf-8
import threading
import time

class Num:
    def __init__(self):
        self.num=0;
    def add(self):
        self.num +=1;
    def get(self):
        return self.num;

class threadingSema(threading.Thread):
    def __init__(self,s,n):
        threading.Thread.__init__(self);
        self.s=s;
        self.n=n;
    def run(self):
        #while(True):
            self.s.acquire();#内部计数器减1
            self.n.add();
            print("当前num=",self.n.get());
            time.sleep(3);
            self.s.release();#内部计数器加1
        
        

if __name__=="__main__":
    n=Num();
    s=threading.Semaphore(3);
    threads=[];
    for i in range(10):
        t=threadingSema(s,n);
        t.setDaemon(True);
        t.start();
        threads.append(t);
    for tt in threads:
        tt.join();
#这是输出,可以看出是每次三个线程,计算结果也正确,三个同时计算结果也没出错。
#出差的只是输出线程间的打断(这个有办法解决么?)
当前num= 1
当前num= 当前num=2 
3
当前num= 4
当前num=当前num= 56
当前num= 7
当前num=当前num= 8
9
当前num= 10

  1. event
    线程间通信的基本功能,更为通用的一种做法是使用threading.Event对象。使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False。一旦该线程通过wait()方法进入等待状态,后面的代码将被阻塞,直到另一个线程调用该Event的set()方法将内置标志设置为True时,该Event会通知所有处于等待状态的线程恢复运行。

#coding=utf-8

import threading,time

class threadingEvent(threading.Thread):
    def __init__(self,name,e):
        threading.Thread.__init__(self);
        self.name=name;
        self.e=e;
    def run(self):
        print("我是%s,我先睡一会\n"%self.name);
        self.e.wait();#默认为False,所以阻塞在这了
        print("我是%s,我被唤醒了\n"%self.name);

if __name__=='__main__':
    event=threading.Event();
    for i in range(3):
        t=threadingEvent('X'+str(i),event);
        t.setDaemon(True);
        t.start();
    print("sleep 5 seconds\n");
    time.sleep(5);
    event.set();#置为True,从wait状态恢复运行
    t.join();
    print("Done !");
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容

  • 概述 这篇博客是我翻译Python threads synchronization: Locks, RLocks,...
    0行痴0阅读 1,445评论 0 8
  • 1.线程的基本概念 1.1 线程 线程是应用程序最小的执行单元,线程与进程类似,进程可以看做程序的一次执行,而线程...
    XYZeroing阅读 959评论 1 16
  • 线程和进程 计算机,用于计算的机器。计算机的核心是CPU,在现在多核心的电脑很常见了。为了充分利用cpu核心做计算...
    人世间阅读 24,309评论 3 85
  • 来源:数据分析网Threading 模块从 Python 1.5.2 版开始出现,用于增强底层的多线程模块 thr...
    PyChina阅读 1,736评论 0 5
  • 概述 多线程给我们带来的好处是可以并发的执行多个任务,特别是对于I/O密集型的业务,使用多线程,可以带来成倍的性能...
    SimonChen阅读 9,412评论 0 5