精华内容
下载资源
问答
  • 多线程 MessageBox.Show()问题

    千次阅读 2012-08-22 22:06:07
    /// 提示信息 public void ShowMessage(string msg) { this.Invoke(new MessageBoxShow(MessageBoxShow_F), new ... MessageBox.Show(msg,"提示信息",MessageBoxButtons.OK,MessageBoxIcon.Information); }
    /// <summary>提示信息</summary>
       public void ShowMessage(string msg)
       {
       this.Invoke(new MessageBoxShow(MessageBoxShow_F), new object [] { msg });
       }
       delegate void MessageBoxShow(string msg);
       void MessageBoxShow_F(string msg)
       {
       MessageBox.Show(msg,"提示信息",MessageBoxButtons.OK,MessageBoxIcon.Information);
       }

    展开全文
  • 在大漠多线程模板中,脚本副线程的作用主要是一个监控线程,可以监控游戏窗口是否存在,游戏是否卡屏,是否掉线,当然你可以用来进行游戏里的其他检测监控。 511遇见易语言多线程大漠多线程 大漠多线程主副线程 ...

    在大漠多线程模板中,脚本副线程的作用主要是一个监控线程,可以监控游戏窗口是否存在,游戏是否卡屏,是否掉线,当然你可以用来进行游戏里的其他检测监控。

    511遇见易语言多线程大漠多线程

    大漠多线程主副线程

    .版本 2
     
    .子程序 脚本副线程, , , 监控线程
    .参数 序号, 整数型
    .局部变量 dm, dmsoft
    .局部变量 dm_ret, 整数型
    .局部变量 死循环, 逻辑型
    .局部变量 任务完成, 文本型
     
    ' 要把大漠插件接口初始化为MAT线程模型
    CoInitializeEx (0, 0)
    线程信息 [序号].线程状态 = #线程状态_正在运行
     
    多线程_异步通知UI (#通知类型_更新, 序号)
    ' 创建对象
    线程信息 [序号].dm.创建 ()
    dm = 线程信息 [序号].dm
     
    .如果真 (dm.Ver () = “”)
        日志输出 (“大漠对象创建失败”)
        设置异常 (序号, “对象创建失败”)
     
        返回 ()
    .如果真结束
     
    ' 开启全局字库
    ' dm.EnableShareDict ()
    ' 设置全局路径
    dm.SetPath (“c:\test”)
    ' 开始绑定游戏窗口,根据自己的游戏换绑定方式
    dm_ret = dm.BindWindowEx (线程信息 [序号].窗口句柄, “normal”, “normal”, “dx”, “dx.public.anti.api|dx.public.disable.window.show”, 0)
    .如果真 (dm_ret ≠ 1)
        日志输出 (“主:绑定失败,错误码:” + 到文本 (dm.GetLastError ()))
        ' 通知主线程进行结束操作(释放资源)
        设置异常 (序号, “绑定失败:副”)
        返回 ()
    .如果真结束
     
    死循环 = 真
    .判断循环首 (死循环)
        ' 可用来检测脚本的异常情况,比如,掉线,目标窗口关闭,
        检测异常 (序号)
        脚本延时 (序号, 1000)
     
    .判断循环尾 ()
     
     
    .子程序 做任务
    .参数 序号
    .局部变量 dm, dmsoft
     
    dm = 线程信息 [序号].dm
    dm.KeyPressChar (“D”)
    脚本延时 (序号, 1000)
     
     
    .子程序 脚本延时
    .参数 序号
    .参数 时间
     
    延时 (时间)

    源码:易语言多线程大漠多线程-37大漠多线程模板-7脚本主副线程

    展开全文
  • 爬虫 第五讲 多线程爬虫

    万次阅读 2021-04-29 15:30:00
    爬虫 第五讲 多线程爬虫 一、多线程 1.多线程基本介绍 有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的。 程序中模拟多任务 import time def sing(): for ...

    爬虫 第五讲 多线程爬虫

    一、多线程

    1.多线程基本介绍

    有很多的生活场景中的事情是同时进行的,比如一边做饭,一边跟别人聊天,一边听歌。

    示例1

    import time
    
    def sing():
        for i in range(3):
            print("正在唱歌...%d" % i)
            time.sleep(1)
    
    def dance():
        for i in range(3):
            print("正在跳舞...%d" % i)
            time.sleep(1)
    
    if __name__ == '__main__':
        sing()
        dance()
    '''
    正在唱歌...0
    正在唱歌...1
    正在唱歌...2
    正在跳舞...0
    正在跳舞...1
    正在跳舞...2
    '''
    

    示例2

    import time
    import threading
    def sing():
        for i in range(3):
            print("正在唱歌...%d" % i)
            time.sleep(1)
    
    def dance():
        for i in range(3):
            print("正在跳舞...%d" % i)
            time.sleep(1)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=sing)
        t2 = threading.Thread(target=dance)
        t1.start()
        t2.start()
    '''
    正在唱歌...0
    正在跳舞...0
    正在唱歌...1
    正在跳舞...1
    正在唱歌...2
    正在跳舞...2
    '''
    

    2.主线程和子线程的执行关系

    主线程会等待子线程结束之后在结束

    import threading
    import time
    
    def demo():
        for i in range(5):
            print('hello 子线程')  # 子线程
            time.sleep(1)
    
    if __name__ == '__main__':
        # 参数1  group 线程组 None
        # 参数2  target 要执行的方法
        # 参数3  name  线程名
        t = threading.Thread(target=demo)
        # 主线程会等待子线程结束之后再结束
        t.start()  # 创建并开启线程
        print(1)
    
    '''
    hello 子线程
    1
    hello 子线程
    hello 子线程
    hello 子线程
    hello 子线程'''
    

    join() 等待子线程结束之后,主线程继续执行

    import threading
    import time
    
    def demo():
        for i in range(5):
            print('hello 子线程')  # 子线程
            time.sleep(1)
    
    if __name__ == '__main__':
        # 参数1  group 线程组 None
        # 参数2  target 要执行的方法
        # 参数3  name  线程名
        t = threading.Thread(target=demo)
        # 主线程会等待子线程结束之后再结束
        t.start()  # 开启线程
        # 等待子进程结束之后,主线程再继续执行
        t.join()
        print(1)
    '''
    hello 子线程
    hello 子线程
    hello 子线程
    hello 子线程
    hello 子线程
    1
    '''
    

    setDaemon() 守护线程,不会等待子线程结束

    import threading
    import time
    def demo():
        for i in range(5):
            print('hello 子线程')  # 子线程
            time.sleep(1)
    
    if __name__ == '__main__':
        # 参数1  group 线程组 None
        # 参数2  target 要执行的方法
        # 参数3  name  线程名
        t = threading.Thread(target=demo)
        # 守护线程,不会等待子线程结束
        t.setDaemon(True)
        # 主线程会等待子线程结束之后再结束
        t.start()  # 开启线程
        print(1)
    '''hello 子线程1'''
    
    import threading
    import time
    def run(num):
        print("子线程(%s)开始" % (threading.current_thread().name))
        # 实现线程的功能
        time.sleep(2)
        print("打印", num)
        time.sleep(2)
        print("子线程(%s)结束" % (threading.current_thread().name))
    
    if __name__ == "__main__":
        # 任何进程默认就会启动一个线程,称为主线程,主线程可以启动新的子线程
        # 打印当前线程的名称,current_thread():返回当前线程的实例
        print("主线程(%s)启动" % (threading.current_thread().name))
        # t.start()创建并启动子线程
        t = threading.Thread(target=run, name="runThread", args=(1,))  # 如果不写 name="runThread",(Thread-1)排下去
        t.start()
        t.join()  # 等待线程结束
        print("主线程(%s)结束" % (threading.current_thread().name))
    '''
    主线程(MainThread)启动
    子线程(runThread)开始
    打印 1
    子线程(runThread)结束
    主线程(MainThread)结束'''
    
    import threading
    import time
    
    def demo():
        # 子线程
        print("hello man")
        time.sleep(1)
    
    if __name__ == "__main__":
        for i in range(5):
            t = threading.Thread(target=demo)
            t.start()
    '''
    hello man
    hello man
    hello man
    hello man
    hello man'''
    

    3.查看线程数量

    threading.enumerate()	查看当前线程的数量
    
    # threading.enumerate  列出活着的线程
    import time
    import threading
    
    def demo1():
        for i in range(5):
            print('demo1-----%d' % i)
            time.sleep(1)
    
    def demo2():
        for i in range(10):
            print('demo2-----%d' % i)
            time.sleep(1)
    
    def main():
        t1 = threading.Thread(target=demo1)
        t2 = threading.Thread(target=demo2)
        t1.start()
        t2.start()
        while True:
            print(threading.enumerate())
            if len(threading.enumerate()) <=1:
                break
            time.sleep(1)
    
    if __name__ == '__main__':
        main()
    '''
    demo1-----0
    demo2-----0[<_MainThread(MainThread, started 11424)>, <Thread(Thread-1, started 11504)>, <Thread(Thread-2, started 11204)>]
    
    demo1-----1
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-1, started 11504)>, <Thread(Thread-2, started 11204)>]
    demo2-----1
    demo1-----2
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-1, started 11504)>, <Thread(Thread-2, started 11204)>]
    demo2-----2
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-1, started 11504)>, <Thread(Thread-2, started 11204)>]
    demo2-----3
    demo1-----3
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-1, started 11504)>, <Thread(Thread-2, started 11204)>]demo2-----4
    
    demo1-----4
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]
    demo2-----5
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]demo2-----6
    
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]
    demo2-----7
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]
    demo2-----8
    demo2-----9[<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]
    
    [<_MainThread(MainThread, started 11424)>, <Thread(Thread-2, started 11204)>]
    [<_MainThread(MainThread, started 11424)>]
    '''
    

    4.验证子线程的执行与创建

    当调用Thread的时候,不会创建线程。
    当调用Thread创建出来的实例对象的start方法的时候,才会创建线程以及开始运行这个线程。

    import threading
    import time
    def demo():
        for i in range(5):
            print('demo-----%d'%i)
            time.sleep(1)
    
    def main():
        print(threading.enumerate())  # 一个主线程
        t1 = threading.Thread(target=demo)  # 创建? 证明它不是创建线程
        print(threading.enumerate())  # 一个主线程
        t1.start()  # 创建线程并启动线程
        print(threading.enumerate())  # 有2个线程,一个是主线程,一个是子线程
    
    
    if __name__ == '__main__':
        main()
    '''
    [<_MainThread(MainThread, started 21084)>]
    [<_MainThread(MainThread, started 21084)>]
    demo-----0[<_MainThread(MainThread, started 21084)>, <Thread(Thread-1, started 11688)>]
    
    demo-----1
    demo-----2
    demo-----3
    demo-----4'''
    

    5.继承Thread类创建线程

    示例1

    import threading
    import time
    
    
    class A(threading.Thread):
    
        def __init__(self, name):
            super().__init__(name=name)
    
        def run(self):
            for i in range(5):
                print(i)
    
    
    if __name__ == "__main__":
        t = A('test_name')
        t.start()
    '''
    0
    1
    2
    3
    4'''
    

    示例2

    import threading
    import time
    class A(threading.Thread):
        def run(self):
            for i in range(4):
                print(i)
    
    
    if __name__ == '__main__':
        a = A()
        print(threading.enumerate())
        a.start()
        print(threading.enumerate())
        time.sleep(5)
        print(123)
        print(threading.enumerate())
    '''
    [<_MainThread(MainThread, started 788)>]
    0[<_MainThread(MainThread, started 788)>, <A(Thread-1, started 7788)>]
    
    1
    2
    3
    123
    [<_MainThread(MainThread, started 788)>]'''
    

    6.线程间的通信(多线程共享全局变量)

    在一个函数中,对全局变量进行修改的时候,是否要加global要看是否对全局变量的指向进行了修改,如果修改了指向,那么必须使用global,仅仅是修改了指向的空间中的数据,此时不用必须使用global
    线程是共享全局变量

    import time
    import threading
    num = 100
    def demo1():
        global num
        num += 1
        print('demo1-nums%d'%num)
    
    def demo2():
        print('demo2-nums%d'%num)
    
    def main():
        t1 = threading.Thread(target=demo1)
        t2 = threading.Thread(target=demo2)
        t1.start()
        time.sleep(1)
        t2.start()
        print('main-nums%d'%num)
    
    if __name__ == '__main__':
        main()
    '''
    demo1-nums101
    demo2-nums101
    main-nums101
    '''
    

    7.线程间的资源竞争

    一个线程写入,一个线程读取,没问题,如果两个线程都写入呢?

    示例

    import time
    import threading
    
    num = 0
    
    
    def demo1(nums):
        global num
        for i in range(nums):
            num += 1
        print('demo1-num %d' % num)
    
    
    def demo2(nums):
        global num
        for i in range(nums):
            num += 1
        print('demo2-num %d' % num)
    
    
    def main():
        t1 = threading.Thread(target=demo1, args=(1000000,))
        t2 = threading.Thread(target=demo2, args=(1000000,))
        t1.start()
        # time.sleep(3)  # 让t1先运行3秒
        t2.start()
        time.sleep(3)
        print('main-num %d' % num)
    
    
    if __name__ == '__main__':
        main()
    '''
    demo2-num 946165
    demo1-num 1144227
    main-num 1144227'''
    
    

    解决资源竞争:在t1.start()之后暂停3秒再执行t2.start(),或者在分别在t1.start()、t2.start()之后加上t1.join(),t2.join() 或者加锁

    加锁,Lock()创建一把锁,默认是没有上锁,这样创建的锁不可重复

    示例

    import time
    import threading
    
    num = 0
    mutex = threading.Lock()  # Lock()创建一把锁,默认是没有上锁,这样创建的锁不可重复
    
    def demo1(nums):
        global num
        # 加锁
        mutex.acquire()
        for i in range(nums):
            num += 1
        # 解锁
        mutex.release()
        print('demo1-num %d' % num)
    
    
    def demo2(nums):
        global num
        # 加锁
        mutex.acquire()
        for i in range(nums):
            num += 1
        # 解锁
        mutex.release()
        print('demo2-num %d' % num)
    
    
    def main():
        t1 = threading.Thread(target=demo1, args=(1000000,))
        t2 = threading.Thread(target=demo2, args=(1000000,))
        t1.start()
        t2.start()
        time.sleep(3)
        print('main-num %d' % num)
    
    
    if __name__ == '__main__':
        main()
    '''
    demo1-num 1000000
    demo2-num 2000000
    main-num 2000000
    '''
    

    加锁,RLock()创建一把锁,默认是没有上锁,这样创建的锁可重复,要对应解锁

    示例

    import time
    import threading
    
    num = 0
    mutex = threading.RLock()  # RLock()创建一把锁,默认是没有上锁,这样创建的锁可重复,要对应解锁
    
    def demo1(nums):
        global num
        # 加锁
        mutex.acquire()
        mutex.acquire()
        for i in range(nums):
            num += 1
        # 解锁
        mutex.release()
        mutex.release()
        print('demo1-num %d' % num)
    
    
    def demo2(nums):
        global num
        # 加锁
        mutex.acquire()
        for i in range(nums):
            num += 1
        # 解锁
        mutex.release()
        print('demo2-num %d' % num)
    
    
    def main():
        t1 = threading.Thread(target=demo1, args=(1000000,))
        t2 = threading.Thread(target=demo2, args=(1000000,))
        t1.start()
        t2.start()
        time.sleep(3)
        print('main-num %d' % num)
    
    
    if __name__ == '__main__':
        main()
    
    '''
    demo1-num 1000000
    demo2-num 2000000
    main-num 2000000
    '''
    

    二、生产者和消费者模型

    1.线程间的资源竞争

    一个线程写入,一个线程读取,没问题,如果两个线程都写入呢?

    互斥锁和死锁

    互斥锁

    当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
    某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

    创建锁
    mutex = threading.Lock()
    
    锁定
    mutex.acquire()
    
    解锁
    mutex.release()
    

    死锁

    在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。

    示例

    # 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
    import threading
    import time
    
    class MyThread1(threading.Thread):
        def run(self):
            # 对mutexA上锁
            mutexA.acquire()
    
            # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
            print(self.name+'----do1---up----')
            time.sleep(1)
    
            # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
            mutexB.acquire()
            print(self.name+'----do1---down----')
            mutexB.release()
    
            # 对mutexA解锁
            mutexA.release()
    
    class MyThread2(threading.Thread):
        def run(self):
            # 对mutexB上锁
            mutexB.acquire()
    
            # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
            print(self.name+'----do2---up----')
            time.sleep(1)
    
            # 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
            mutexA.acquire()
            print(self.name+'----do2---down----')
            mutexA.release()
    
            # 对mutexB解锁
            mutexB.release()
    
    mutexA = threading.Lock()
    mutexB = threading.Lock()
    
    if __name__ == '__main__':
        t1 = MyThread1()
        t2 = MyThread2()
        t1.start()
        t2.start()
    '''
    执行结果:打印如下,不会结束程序
    Thread-1----do1---up----
    Thread-2----do2---up----
    '''
    
    

    避免死锁

    • 程序设计时要尽量避免
    • 添加超时时间等

    2.Queue线程

    在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列中,那么Python内置了一个线程安全的模块叫做queue模块。Python中的queue模块中提供了同步的、线程安全的队列类,包括FIFO(先进先出)队列Queue,LIFO(后入先出)队列LifoQueue。这些队列都实现了锁原语(可以理解为原子操作,即要么不做,要么都做完),能够在多线程中直接使用。可以使用队列来实现线程间的同步。

    # 初始化Queue(maxsize):创建一个先进先出的队列。
    # empty():判断队列是否为空。
    # full():判断队列是否满了。
    # get():从队列中取最后一个数据。
    # put():将一个数据放到队列中。
    from queue import Queue
    
    q = Queue()
    print(q.empty())  # True  空的队列
    print(q.full())  # False  不是满的队列
    # --------------------------分隔线--------------------------------------
    q1 = Queue()
    q1.put(1)  # 将数字1放到队列中
    print(q1.empty())  # False  不是空的队列
    print(q1.full())  # False  不是满的队列
    # --------------------------分隔线--------------------------------------
    q2 = Queue(3)  # 指定为长度为3
    q2.put(1)
    q2.put(2)
    q2.put(3)
    print(q2.empty())  # False  不是空的队列
    print(q2.full())  # True  是满的队列
    # --------------------------分隔线--------------------------------------
    q3 = Queue(3)  # 指定为长度为3
    q3.put(1)
    q3.put(2)
    q3.put(3)
    q3.put(4, timeout=3)  # 超出队列的长度,不加timeout程序将阻塞,加timeout=3,3秒后抛出异常 queue.Full
    # --------------------------分隔线--------------------------------------
    from queue import Queue
    
    q4 = Queue(3)  # 指定为长度为3
    q4.put(1)
    q4.put(2)
    q4.put(3)
    q4.put_nowait(4)  # 超出队列的长度,直接抛出异常queue.Full
    # --------------------------分隔线--------------------------------------
    q5 = Queue(3)  # 指定为长度为3
    q5.put(1)
    q5.put(2)
    q5.put(3)
    print(q5.get())  # 1
    print(q5.get())  # 2
    print(q5.get())  # 3
    print(q5.get(timeout=3))  # 超出队列,程序将阻塞,添加timeout=3,3秒后抛出异常_queue.Empty
    # --------------------------分隔线--------------------------------------
    q6 = Queue(3)  # 指定为长度为3
    q6.put(1)
    q6.put(2)
    q6.put(3)
    print(q6.get())  # 1
    print(q6.get())  # 2
    print(q6.get())  # 3
    print(q6.get_nowait())  # 超出队列的长度,直接抛出异常_queue.Empty
    

    3.生产者和消费者

    生产者和消费者模式是多线程开发中常见的一种模式。通过生产者和消费者模式,可以让代码达到高内聚低耦合的目标,线程管理更加方便,程序分工更加明确。
    生产者的线程专门用来生产一些数据,然后存放到容器中(中间变量)。消费者在从这个中间的容器中取出数据进行消费
    在这里插入图片描述

    Lock版的生产者和消费者

    import threading
    import random
    import time
    gMoney = 0
    gTimes = 0  # 定义一个变量 保存生产的次数 默认是0次
    gLock = threading.Lock()  # 定义一把锁
    
    # 定义生产者
    class Producer(threading.Thread):
    
        def run(self) -> None:
            global gMoney
            global gTimes
            # gLock.acquire()  # 上锁
            while True:
                gLock.acquire()  # 上锁
                if gTimes >= 10:
                    gLock.release()
                    break
                money = random.randint(0, 100)  # 0 <= money <= 100
                gMoney += money
                gTimes += 1
                # threading.current_thread().name 获取当前线程的名称
                print("%s生产了%d元钱,累计%d元" % (threading.current_thread().name, money, gMoney))
                gLock.release()  # 解锁
                time.sleep(1)
    # 定义消费者
    class Consumer(threading.Thread):
        def run(self) -> None:
            global gMoney
            while True:
                gLock.acquire()  # 上锁
                money = random.randint(0, 100)  # 0 <= money <= 100
                if gMoney >= money:
                    gMoney -= money
                    # threading.current_thread().name 获取当前线程的名称
                    print("%s消费了%d元钱,余额:%d元" % (threading.current_thread().name, money, gMoney))
                else:
                    if gTimes >= 10:
                        gLock.release()
                        break
                    print("%s想消费%d元钱,但是余额只有%d元,不能消费" % (threading.current_thread().name, money, gMoney))
                gLock.release()  # 解锁
                time.sleep(1)
    
    def main():
        # 开启5个生产者线程
        for i in range(5):
            th = Producer(name="生产者%d号" % i)
            th.start()
        # 开启5个消费者线程
        for i in range(5):
            th = Consumer(name="消费者%d号" % i)
            th.start()
    
    if __name__ == '__main__':
        main()
    
    '''
    生产者0号生产了13元钱,累计13元
    生产者1号生产了77元钱,累计90元
    生产者2号生产了56元钱,累计146元
    生产者3号生产了39元钱,累计185元
    生产者4号生产了10元钱,累计195元
    消费者0号消费了48元钱,余额:147元
    消费者1号消费了92元钱,余额:55元
    消费者2号想消费88元钱,但是余额只有55元,不能消费
    消费者3号想消费68元钱,但是余额只有55元,不能消费
    消费者4号消费了15元钱,余额:40元
    生产者2号生产了77元钱,累计117元
    消费者1号消费了99元钱,余额:18元
    生产者1号生产了79元钱,累计97元
    消费者0号消费了79元钱,余额:18元
    消费者4号想消费40元钱,但是余额只有18元,不能消费
    生产者0号生产了65元钱,累计83元
    生产者4号生产了29元钱,累计112元
    消费者3号消费了64元钱,余额:48元
    生产者3号生产了95元钱,累计143元
    消费者2号消费了73元钱,余额:70元
    消费者1号消费了13元钱,余额:57元
    消费者4号消费了48元钱,余额:9元
    消费者1号消费了1元钱,余额:8元
    '''
    '''
    

    Condition版的生产者和消费者

    # 相对Lock版的生产者和消费者,Lock版消耗资源更多。Condition增加了阻塞等待
    import threading
    import random
    import time
    gMoney = 0
    # 定义一个变量 保存生产的次数 默认是0次
    gTimes = 0
    # 定义一把锁
    gCond = threading.Condition()
    
    # 定义生产者
    class Producer(threading.Thread):
        def run(self) -> None:
            global gMoney
            global gTimes
            # gLock.acquire()  # 上锁
            while True:
                gCond.acquire()  # 上锁
                if gTimes >= 10:
                    gCond.release()
                    break
                money = random.randint(0, 100)  # 0 <= money <= 100
                gMoney += money
                gTimes += 1
                print("%s生产了%d元钱,累计%d元" % (threading.current_thread().name, money, gMoney))
                gCond.notifyAll()  # 通知所有
                gCond.release()  # 解锁
                time.sleep(1)
    # 定义消费者
    class Consumer(threading.Thread):
        def run(self) -> None:
            global gMoney
            while True:
                gCond.acquire()  # 上锁
                money = random.randint(0, 100)
                while gMoney < money:
                    if gTimes >= 10:
                        gCond.release()  # 解锁
                        return  # 这里如果用break退出了内循环,但是外层循环没有退出,直接用return
                    print("%s想消费%d元钱,但是余额只有%d元,不能消费" % (threading.current_thread().name, money, gMoney))
                    gCond.wait()  # 等待
                # 开始消费
                gMoney -= money
                print("%s消费了%d元钱,余额:%d元" % (threading.current_thread().name, money, gMoney))
                gCond.release()  # 解锁
                time.sleep(1)
    def main():
        # 开启5个生产者线程
        for i in range(5):
            th = Producer(name="生产者%d号" % i)
            th.start()
        # 开启5个消费者线程
        for i in range(5):
            th = Consumer(name="消费者%d号" % i)
            th.start()
    
    if __name__ == '__main__':
        main()
    
    '''
    生产者0号生产了28元钱,累计28元
    生产者1号生产了0元钱,累计28元
    生产者2号生产了94元钱,累计122元
    生产者3号生产了68元钱,累计190元
    生产者4号生产了29元钱,累计219元
    消费者0号消费了35元钱,余额:184元
    消费者1号消费了96元钱,余额:88元
    消费者2号消费了33元钱,余额:55元
    消费者3号消费了51元钱,余额:4元
    消费者4号想消费75元钱,但是余额只有4元,不能消费
    生产者1号生产了63元钱,累计67元
    生产者3号生产了57元钱,累计124元
    消费者2号消费了75元钱,余额:49元
    消费者1号想消费90元钱,但是余额只有49元,不能消费
    生产者2号生产了84元钱,累计133元
    消费者1号消费了90元钱,余额:43元
    生产者0号生产了40元钱,累计83元
    消费者0号消费了43元钱,余额:40元
    生产者4号生产了3元钱,累计43元
    消费者1号消费了4元钱,余额:39元
    消费者2号消费了19元钱,余额:20元
    消费者0号消费了18元钱,余额:2元
    '''
    

    三、多线程爬取王者荣耀高清壁纸案例

    import os
    import queue
    from urllib import parse
    from urllib.request import urlretrieve
    import requests
    import threading
    
    headers = {
        'referer':'https://pvp.qq.com/',
        'user-agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'
    }
    
    all_name_list = []
    num = 0
    
    # 定义生产者
    class Producer(threading.Thread):
        def __init__(self, page_queue, image_queue, *args, **kwargs):
            super(Producer, self).__init__(*args, **kwargs)
            self.page_queue = page_queue
            self.image_queue = image_queue
    
        def run(self) -> None:
            while not self.page_queue.empty():
                page_url = self.page_queue.get()
                reponse = requests.get(page_url, verify=False, headers=headers).json()
                result = reponse['List']
                for data in result:
                    # 获取图片的url
                    image_urls = extract_images(data)
                    # 获取图片名字
                    name = parse.unquote(data['sProdName']).replace('1:1', '').strip()
                    # name = parse.unquote(data['sProdName']).strip() 引发下面报错
                    # FileNotFoundError: [WinError 3] 系统找不到指定的路径。: '1:1等身雕塑·铠'
                    while name in all_name_list:  # 判断是否重名
                        name = name + str(num + 1)
                    all_name_list.append(name)
                    # 创建文件夹
                    dir_path = os.path.join('image', name)  # dir_path = 'image/%s' % name 也可以
                    if not os.path.exists(dir_path):
                        os.mkdir(dir_path)
                    # 把图片的url放进队列里
                    for index, image_url in enumerate(image_urls):
                        self.image_queue.put(
                            {'image_url': image_url, 'image_path': os.path.join(dir_path, '%d.jpg' % (index + 1))})
    
    
    # 定义消费者
    class Consumer(threading.Thread):
        def __init__(self, image_queue, *args, **kwargs):
            super(Consumer, self).__init__(*args, **kwargs)
            self.image_queue = image_queue
    
        def run(self) -> None:
            failed_image_obj = []  # 空列表存放下载失败的image_url和image_path
            while True:
                try:
                    # 获取图片的url和下载路径
                    image_obj = self.image_queue.get(timeout=10)
                    image_url = image_obj.get('image_url')
                    image_path = image_obj.get('image_path')
                    # 下载图片
                    try:
                        urlretrieve(image_url, image_path)
                        print(image_path, '下载完成!')
                    except:
                        print(image_path, '下载失败!')
                        failed_image_obj.append((image_url, image_path))
                except:
                    break
            for item in failed_image_obj:  # 最后再次尝试下载失败的图片
                try:
                    urlretrieve(item[0], item[1])
                    print(item[1], '再次下载,终于成功了!')
                except:
                    print(item[0], item[1], '还是下载失败!')
    
    
    def extract_images(data):
        image_urls = []
        for i in range(1, 9):
            image_url = parse.unquote(data['sProdImgNo_%d' % i]).rstrip('200') + '0'
            # image_url = parse.unquote(data['sProdImgNo_%d' % i]).replace('200', '0')
            image_urls.append(image_url)
        return image_urls
    
    
    def main():
        # 创建页数的队列
        page_queue = queue.Queue(25)
        # 创建图片的队列
        image_queue = queue.Queue(1000)
    
        for i in range(25):
            url = 'https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&iSortNumClose=1&&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735'.format(
                i)
            # 把页数url添加到页数的队列中
            page_queue.put(url)
        # 定义3个生产者线程
        for i in range(3):
            p = Producer(page_queue, image_queue)
            p.start()
    
        # 定义8个消费者线程
        for i in range(8):
            c = Consumer(image_queue)
            c.start()
    
    
    if __name__ == '__main__':
        main()
    
    

    得到全部数据:
    在这里插入图片描述

    展开全文
  • Java多线程

    千次阅读 2021-01-21 15:16:40
    目录 一、实验目的 二、实验代码 1. 通过继承Thread类的方法创建两个线程,在Thread构造方法中指定线程的名称,并将这两个线程的名字打印出来。 2. 通过实现Runnable接口的...1. 掌握Java多线程的创建及其启动..

    目录

    一、实验目的

    二、实验代码

    1. 通过继承Thread类的方法创建两个线程,在Thread构造方法中指定线程的名称,并将这两个线程的名字打印出来。

    2. 通过实现Runnable接口的方法创建一个新线程,要求main线程打印100次“main”,新线程打印50次“new”。

    3. 模拟三个老师同时发80份学习笔记本,每次只发放一份笔记本,每个老师相当于一个线程。

    4. 编写如图6-1所示的界面,当程序运行时:

    每文一语


     

     

    一、实验目的

    1. 掌握Java多线程的创建及其启动,多线程的两种常用创建方式及其区别;

    2. 掌握多线程的生命周期及五种基本状态,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Dead);

    3. 掌握引起Java线程阻塞的主要方法,如:jion()方法、sleep()方法、yeild()方法;

    4. 掌握线程安全及其解决机制,如:同步方法、同步代码块等。

    二、实验代码

    1. 通过继承Thread类的方法创建两个线程,在Thread构造方法中指定线程的名称,并将这两个线程的名字打印出来。

    package 作业练习.test6;
    public class Study_1 extends Thread {
        public Study_1(String name) {
            super(name);
        }
        public void run() {
            System.out.println(this.getName());
        }
        public static void main(String[] args) {
            new Study_1("Thread1").start();
            new Study_1("Thread2").start();
        }
    }
    

    2. 通过实现Runnable接口的方法创建一个新线程,要求main线程打印100次“main”,新线程打印50次“new”。

    package 作业练习.test6;
    
    public class Study_2 implements Runnable {
        public void run() {
            for (int i = 0; i < 50; i++) {
                System.out.println("new");
            }
        }
        public static void main(String[] args) {
            new Thread(new Study_2()).start();
            for (int i = 0; i < 100; i++) {
                System.out.println("main");
            }
        }
    }
    

    3. 模拟三个老师同时发80份学习笔记本,每次只发放一份笔记本,每个老师相当于一个线程。

    package 作业练习.test6;
    public class Study_3 implements Runnable {
        private int number = 80;  //总共80份学习笔记
        private int count = 0;    //发第几份
        @Override
        public void run() {
            while (true) {
                synchronized (this) {
                    if (number <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    number--;
                    count++;
                    System.out.println(Thread.currentThread().getName() + "正在发第" + count + "份学习笔记,还有" + number + "份学习笔记。");
                }
            }
        }
        public static void main(String[] args) {
            Study_3 homeWork3 = new Study_3();
            new Thread(homeWork3, "老师甲").start();
            new Thread(homeWork3, "老师乙").start();
            new Thread(homeWork3, "老师丙").start();
        }
    }
    

    4. 编写如图6-1所示的界面,当程序运行时:

    1)每隔两秒钟在显示字母区域随机显示一个字母(如图所示,显示的字母是“g”);

    2)用户在文本框中使用输入相应的字母,如果输入正确则得1分,否则得0分;

    3)并将用户的得分累计显示在的得分栏。

    package 作业练习.test6;
    
    import javafx.application.Application;
    import javafx.event.EventHandler;
    import javafx.scene.input.KeyCode;
    import javafx.stage.Stage;
    
    import java.awt.*;
    import java.awt.event.KeyEvent;
    
    public class Text4 extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage stage) {
            Label l1 = new Label("显示字母:");
            TextField l2 = new TextField("A");
            l2.setEditable(false);
            l2.setPrefWidth(30.0);//文本框大小
            Label l3 = new Label("输入所显示的字母(回车)");
            TextField l4 = new TextField();
            Label l5 = new Label("得分");
            Label l6 = new Label("0");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        char str;
                        str = (char)(Math.random()*26+'a');
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        String s = String.valueOf(str);
                        l2.setText(s);
                    }
                }
            }).start();
    
            l4.setOnKeyPressed(new EventHandler<KeyEvent>() {
                @Override
                public void handle(KeyEvent e) {
                    if (e.getCode()== KeyCode.ENTER){
                        String text1 = l2.getText();
                        String text2 = l4.getText();
                        String text3 = l6.getText();
                        int i = Integer.parseInt(text3);
                        if (text1.equals(text2)){
                            i+=1;
                            l6.setText(String.valueOf(i));
    
                        }
                    }
                    l4.clear();
                }
            });
    
    
            FlowPane flowPane = new FlowPane();    //添加面板
            flowPane.getChildren().addAll(l1,l2,l3,l4,l5,l6);    //吧空控件添加到面板上
            Scene scene = new Scene(flowPane);   //创建场景
            stage.setScene(scene);   //吧场景添加到舞台
            stage.setWidth(900);
            stage.show();
    
        }
    }
    

    每文一语

    有些东西,只有有了遗憾才会懂得珍惜!

    展开全文
  • QT 多线程应用

    千次阅读 2019-03-10 18:17:31
    QT多线程的实现有两种方法,一种是继承QThread的多线程使用方法,另外一种是使用QObject实现多线的方法。传统的方式是继承QTread,但是这种方式比较的容易出错,QT官方推荐使用的是第二种方式。这里介绍这两种方式的...
  • wxpython多线程

    千次阅读 2019-05-21 15:52:10
    例如python3多线程threading功能强大,结合jion()和setDaemon()函数使用更灵活,使用多线程时首先想到了threading, 但wxpython是用python写的一个UI框架,其本身自带有多线程函数: wx.PostEvent wx.CallAfter wx....
  • C# 线程 winform Show和ShowDialog

    千次阅读 2018-01-31 10:55:17
    说明:在多线程中收到消息后弹出提示框,提示框使用Form进行设计。 问题点描述: 1、Show:添加的控件都显示不出来,出现的效果如下图: 解决:首次解决时,调用Show()之后调用Update()即可显示,但是界面仍然...
  • c++多线程编程与MFC多线程编程

    千次阅读 2012-03-16 15:52:18
    源代码1:http://download.csdn.net/detail/nuptboyzhb/4160217 源码2:...   (一)有关多线程的WIN32 API函数 1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
  • Java 多线程

    千次阅读 2017-08-27 12:57:29
    多线程能使程序高效率利用CPU资源。
  • JAVA多线程基础

    千次阅读 2021-03-19 17:56:43
    JAVA多线程基础 1.什么是并发原理? 多线程多线程允许我们“同时”执行多段代码。 线程是并发运行的,线程调度会统一规划CPU时间,将CPU的时间划分为若干片段,然后尽可能的均匀分配给所要并发运行的线程,每个...
  • 首先是多线程模块的多种制作方法...1、易语言大漠多线程播单地址:http://list.youku.com/albumlist/show/id_49750716 2、易语言大漠游戏外挂一键登录播单地址:http://list.youku.com/albumlist/show/id_49486131 3..
  • C#多线程编程

    千次阅读 2014-06-14 11:47:27
    本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发。 其中委托的BeginInvoke方法以及回调函数最为常用。 而 I/O线程可能容易遭到大家的忽略,其实在...
  • 多线程

    千次阅读 2014-06-03 15:41:14
    本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发。 其中委托的BeginInvoke方法以及回调函数最为常用。 而 I/O线程可能容易遭到大家的忽略,其实在...
  • Java多线程游戏仿真实例分享

    万次阅读 多人点赞 2021-02-02 18:20:57
    多线程的创建、多线程的应用、多线程的特点以及多线程的注意事项) 2、如何让小球在画面中真实地动起来?(赋予小球匀速直线、自由落体、上抛等向量运动) 3、多线程游戏仿真实例分享(飞机大战、接豆人、双线挑战...
  • 多线程调试

    千次阅读 2013-12-25 11:18:19
    10.3.3 调试多线程应用程序 多线程应用程序是在给定的进程中有多于一个的线程在运行的应用程序。默认情况下,每个运行应用程序的进程有至少一个执行线程。你也许创建多个线程来做并行处理。这可以显著地提升性能...
  • QT多线程编程详解

    万次阅读 多人点赞 2019-04-24 22:08:20
    一、线程基础 1、GUI线程与工作线程 每个程序启动后拥有的第一个线程称为主线程,即GUI线程。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次...二、QT多线程简介 QT通过三种形式提供了对线程...
  • Android多线程断点续传

    千次阅读 2016-07-13 20:34:48
    我们编写的是Andorid的HTTP协议...使用多线程的好处:使用多线程下载会提升文件下载的速度。那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度。 HttpURLConnection.getContentLengt
  • Python多线程(自学必备 超详细)

    万次阅读 2021-06-06 00:21:42
    多线程技术 多任务 1.1 多任务的概念 多任务:在同一时间内执行多个任务[可以把每个任务理解为生活当中的每个活] 1.2 现实生活中的多任务 操作系统可以同时运行多个任务。比如,你一边打游戏,一边和队友沟通,这...
  • java多线程

    千次阅读 2016-05-25 10:21:37
    刚开始学多线程也是有点点蒙的感觉,就是学了就忘,因为本人还没毕业,大学的时候都是自学的,建议刚开始先理解再看视频或资料 一些定义:
  • 多线程多个实例

    千次阅读 2018-01-13 10:44:55
     正常的情况下,线程在运行时线程之间执行任务的时机是无序的。可以通过改造代码的方式使它们运行具有有序性。 public class MyThread extends Thread { private Object lock; private String showChar; ...
  • C++多线程(二)(_beginThreadex创建多线程)  C/C++ Runtime 多线程函数 一 简单实例(来自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
  • c#多线程

    千次阅读 2012-07-04 12:29:49
    本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发。 其中委托的BeginInvoke方法以及回调函数最为常用。 而 I/O线程可能容易遭到大家的忽略,其实在...
  • C#多线程编程总结

    千次阅读 多人点赞 2020-07-20 11:26:36
    一个最直接的方法便是使用多线程多线程编程的方式在WinForm开发中必不可少。 本文介绍在WinForm开发中如何使用多线程,以及在线程中如何通过Control.Invoke方法返回窗体主线程执行相关操作。 -. WinForm多线程...
  • QSerialport多线程方法

    千次阅读 2019-05-20 07:19:42
    QSerialport多线程方法 使用Qt也已经有一段时间了,虽然使用过继承QThread重写run函数,以及继承QObject然后使用MoveToThread两种方法实现多线程,但是在QSerialPort的使用过程中,两种方法都存在一定的问题。 ...
  • VB.NET多线程入门

    千次阅读 2015-12-07 20:54:56
    最近项目中遇到了一个处理速度慢堵塞用户界面操作的问题,因此想用多线程来解决。 在处理数据的循环中,新建线程,在新建的线程中处理数据。多线程同时处理数据,以此来达到加速的目的。 在多任务操作系统中,我们...
  • Python threading Thread多线程的使用方法

    千次阅读 2019-03-13 16:36:18
    Python threading Thread多线程的使用方法 参考资料:《Python 多线程》http://www.runoob.com/python/python-multithreading.html 目录 Python threading Thread多线程的使用方法 1.使用Threading模块创建线程 ...
  • show full processlist; 这个命令中最关键的就是state列,mysql列出的状态主要有以下几种: Checking table  正在检查数据表(这是自动的)。 Closing tables  正在将表中修改的数据刷新到磁盘中,同时正在关闭...
  • Qt开启多线程

    千次阅读 2019-04-23 09:42:58
    Qt开启多线程,主要用到类QThread。有两种方法,第一种用一个类继承QThread,然后重新改写虚函数run()。当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程。第二种方法是继承一个...
  • java实现多线程

    千次阅读 2014-02-28 10:19:34
    要实现多线程需要先明白什么是多线程? 线程就是进程中的顺序控制流,多线程自然就是同一个进程中有多个顺序控制流了。其实当JVM启动时已经开启了至少两个线程,一个用来执行main函数的线程,另外一个用来进行垃圾...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 161,415
精华内容 64,566
关键字:

多线程show