• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

并发编程 – 线程

python 搞java代码 3年前 (2022-05-21) 18次浏览 已收录 0个评论

并发编程 – 线程

1、什么是线程

  进程:资源单位

  线程:执行单位

 

  线程与进程都是虚拟的概念,只是为了更好地表达某种事物

 

  注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者

 

 

2、为什么要使用线程

  > 为了节省资源的占用

  > 多线程执行速度非常快 

 

  开启进程会发生什么:

    > 启动进程会产生一个内存空间,申请一块资源

    > 会自带一个主线程

    > 开启子进程的速度要比开启子线程的速度慢

  开启线程会发生什么:

    > 一个进程内可以开启多个线程,从进程的内存空间中申请资源

    > 节省资源

  # 比如开启三个进程:

    # 占用三分内存资源

  # 比如开启三个线程:

    # 从一个内存资源中,申请三个小的执行单位

 

  问题1:在单核情况下,开启多进程有没有提高执行效率?

    没有,在单核情况下,尽量开启多线程。

 

  问题:IO密集型、计算密集型分别使用什么?

    IO密集型:多线程

      IO(时间由用户决定):

        阻塞:切换+保存状态

    计算密集型:多进程

      计算(时间由操作系统定):

        计算时间很长:切换+保存状态

 

  注意:进程与进程之间数据是隔离的,线程与线程之间的数据是共享的

 

 

3、线程的两种创建方式、守护线程

  守护线程的使用方式和守护进程的使用方式一样,在下面创建线程中体现:

 

  第一种方式:直接调用Thread类

<span>from</span> threading <span>import</span> Thread    <span>#</span><span> Thread用来创建线程</span>
<span>from</span> threading <span>import</span> current_thread    <span>#</span><span> current_thread中含有线程的属性</span>
<span>import</span><span> time

</span>
<span>def</span><span> task():
    </span><span>print</span>(f<span>"</span><span>start...{current_thread().name}</span><span>"</span>)    <span>#</span><span> current_thread().name 线程的名字</span>
    time.sleep(1<span>)
    </span><span>print</span>(f<span>"</span><span>end...{current_thread().name}</span><span>"</span>)    <span>#</span><span> current_thread().name 线程的名字</span>


<span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    </span><span>#</span><span> 模拟开启10个子线程</span>
    <span>for</span> i <span>in</span> range(10<span>):
        </span><span>#</span><span> 开启子线程</span>
        t = Thread(target=<span>task)
        </span><span>#</span><span> 加上守护线程:主进程结束,代表主线程也结束,子线程有可能会被回收,将其他线程回收资源</span>
        t.daemon =<span> True
        t.start()
        </span><span>#</span><span> 告诉主线程等到子线程执行完成再执行主线程</span>
<span>        t.join()

    </span><span>print</span>(f<span>"</span><span>主进程(主线程)结束...{current_thread().name}</span><span>"</span>)    <span>#</span><span> current_thread().name 线程的名字</span>

www#gaodaima.com来源gaodai$ma#com搞$代*码网搞代码

  执行结果:

start...Thread-1<span>
end...Thread</span>-1<span>
start...Thread</span>-2<span>
end...Thread</span>-2<span>
start...Thread</span>-3<span>
end...Thread</span>-3<span>
start...Thread</span>-4<span>
end...Thread</span>-4<span>
start...Thread</span>-5<span>
end...Thread</span>-5<span>
start...Thread</span>-6<span>
end...Thread</span>-6<span>
start...Thread</span>-7<span>
end...Thread</span>-7<span>
start...Thread</span>-8<span>
end...Thread</span>-8<span>
start...Thread</span>-9<span>
end...Thread</span>-9<span>
start...Thread</span>-10<span>
end...Thread</span>-10<span>
主进程(主线程)结束...MainThread</span>

 

  第二种方式:继承Thread类

<span>from</span> threading <span>import</span> Thread    <span>#</span><span> Thread用来创建线程</span>
<span>from</span> threading <span>import</span> current_thread    <span>#</span><span> current_thread中含有线程的属性</span>
<span>import</span><span> time


</span><span>class</span><span> MyThread(Thread):

    </span><span>def</span><span> run(self):
        </span><span>print</span>(f<span>"</span><span>start...{current_thread().name}</span><span>"</span>)  <span>#</span><span> current_thread().name 线程的名字</span>
        time.sleep(1<span>)
        </span><span>print</span>(f<span>"</span><span>end...{current_thread().name}</span><span>"</span>)  <span>#</span><span> current_thread().name 线程的名字</span>


<span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    </span><span>#</span><span> 开启子线程</span>
    t =<span> MyThread()
    </span><span>#</span><span> 加上守护线程:主进程结束,代表主线程也结束,子线程有可能会被回收,将其他线程回收资源</span>
    t.daemon =<span> True
    t.start()
    </span><span>#</span><span> 告诉主线程等到子线程执行完成再执行主线程</span>
<span>    t.join()

    </span><span>print</span>(f<span>"</span><span>主进程(主线程)结束...{current_thread().name}</span><span>"</span>)    <span>#</span><span> current_thread().name 线程的名字</span>

  执行结果:

start...Thread-1<span>
end...Thread</span>-1<span>
主进程(主线程)结束...MainThread</span>

 

 

4、线程间数据是互通的

<span>from</span> threading <span>import</span><span> Thread
</span><span>import</span><span> time


number </span>= 100
<span>def</span><span> task():
    </span><span>global</span><span> number
    number </span>+= 100
    <span>print</span>(<span>"</span><span>start...</span><span>"</span><span>)
    time.sleep(</span>1<span>)
    </span><span>print</span>(<span>"</span><span>end...</span><span>"</span><span>)


</span><span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    </span><span>#</span><span> 开启子线程</span>
    t = Thread(target=<span>task)
    t.start()
    </span><span>#</span><span> 告诉主线程等到子线程执行完成再执行主线程</span>
<span>    t.join()

    </span><span>print</span>(<span>"</span><span>主进程(主线程)开始...</span><span>"</span><span>)
    </span><span>print</span><span>(number)</span><span>print</span>(<span>"</span><span>主进程(主线程)结束...</span><span>"</span>)

  执行结果:

<span>start...
end...
主进程(主线程)开始...
</span>200<span>
主进程(主线程)结束...</span>

 

 

5、线程互斥锁

  互斥锁是一把锁,将并发编程串行,牺牲了效率,保证了数据读写安全

  多线程实现并发会造成数据不安全,可以使用互斥锁来避免这种问题

 

  例:开启十个线程,对一个数据进行修改

<span>from</span> threading <span>import</span><span> Thread
</span><span>from</span> threading <span>import</span><span> Lock
</span><span>import</span><span> time


number </span>= 100

<span>def</span><span> task(lock):
    </span><span>global</span><span> number
    </span><span>#</span><span> 加锁</span>
<span>    lock.acquire()
    number2 </span>=<span> number
    time.sleep(</span>0.5<span>)
    number </span>= number2 - 1
    <span>#</span><span> 释放锁</span>
<span>    lock.release()


</span><span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    lock </span>=<span> Lock()
    list1 </span>=<span> []
    </span><span>for</span> i <span>in</span> range(10<span>):
        t </span>= Thread(target=task, args=<span>(lock, ))
        t.daemon </span>=<span> True
        t.start()
        list1.append(t)

    </span><span>for</span> t <span>in</span><span> list1:
        t.join()

    </span><span>print</span>(number)

  执行结果:

90

 

 

6、线程池

  作用:用来限制线程的数量,保证了硬件跟得上软件的发展

 

<span>from</span> concurrent.futures <span>import</span><span> ThreadPoolExecutor

</span><span>#</span><span> pool限制一次只能创建10个线程,如果要创建50个线程,就要分成5次创建</span>
pool = ThreadPoolExecutor(10<span>)<br></span><span>def</span><span> task(i):
    </span><span>print</span><span>(i)


</span><span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    </span><span>#</span><span> 开启50个线程</span>
    <span>for</span> i <span>in</span> range(50<span>):<br>     <span># submit(函数名, 参数)方法实现并发</span>
        pool.submit(task, </span>123)

  执行结果:

123
123
123
123
123
123
123
123
123
123
123123

123
123
123
123
123
123
123123
123
123
123123
123
123
123
123


123
123
123
123
123
123
123123123
123
123
123
123
123
123
123

123
123
123
123
123
123

 

 

7、线程池中的回调函数callback

<span>from</span> concurrent.futures <span>import</span><span> ThreadPoolExecutor


</span><span>#</span><span> 并发执行的任务</span>
<span>def</span><span> task1():
    </span><span>return</span> <span>"</span><span>壹贰弎肆伍陆柒捌玖拾</span><span>"</span>


<span>#</span><span> 自定义回调函数</span>
<span>def</span> task2(obj):    <span>#</span><span> obj对象中的result方法会返回 "壹贰弎肆伍陆柒捌玖拾"</span>
    result = obj.result()    <span>#</span><span> "壹贰弎肆伍陆柒捌玖拾"</span>
    <span>print</span><span>(result)


</span><span>if</span> <span>__name__</span> == <span>"</span><span>__main__</span><span>"</span><span>:
    pool </span>= ThreadPoolExecutor(5<span>)
    </span><span>for</span> i <span>in</span> range(5<span>):
        </span><span>#</span><span> pool.submit(函数名).add_done_callback(回调函数的名字)</span>
        <span>#</span><span> submit(函数名, 函数接收的参数1, 参数2...)</span>
        pool.submit(task1).add_done_callback(task2)

  执行结果:

<span>壹贰弎肆伍陆柒捌玖拾
壹贰弎肆伍陆柒捌玖拾
壹贰弎肆伍陆柒捌玖拾
壹贰弎肆伍陆柒捌玖拾
壹贰弎肆伍陆柒捌玖拾</span>

 

  PS:进程池中的回调函数和线程池中的回调函数使用方式一样

 


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:并发编程 – 线程

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址