ฉันจะใช้เธรดใน Python ได้อย่างไร


1279

ฉันพยายามเข้าใจเธรดใน Python ฉันได้ดูเอกสารและตัวอย่าง แต่ค่อนข้างตรงไปตรงมาตัวอย่างมากมายซับซ้อนเกินไปและฉันมีปัญหาในการทำความเข้าใจ

คุณแสดงให้เห็นอย่างชัดเจนถึงภารกิจที่ถูกแบ่งเป็นหลายเธรดได้อย่างไร


31
การสนทนาทั่วไปที่ดีเกี่ยวกับหัวข้อนี้สามารถพบได้ใน ปัญหาที่ยากที่สุดของ Pythonโดย Jeff Knupp โดยสรุปดูเหมือนว่าการทำเกลียวไม่ใช่สำหรับผู้เริ่มต้น
Matthew Walker

112
ฮ่าฮ่าฉันมักจะคิดว่าการทำเกลียวสำหรับทุกคน แต่ผู้เริ่มต้นไม่ได้ทำเกลียว :))))))
Bohdan

42
เพียงเพื่อตั้งค่าสถานะที่ผู้คนควรอ่านคำตอบทั้งหมดในภายหลังว่าเนื้อหาจะดีกว่าเนื่องจากคุณสมบัติภาษาใหม่ได้รับประโยชน์จาก ...
Gwyn Evans

5
อย่าลืมเขียนตรรกะหลักของคุณใน C และเรียกมันผ่าน ctypes เพื่อรับประโยชน์จากการทำเกลียวหลาม
aaa90210

4
ฉันแค่อยากจะเพิ่มว่าPyPubSubเป็นวิธีที่ยอดเยี่ยมในการส่งและรับข้อความเพื่อควบคุมการไหลของเธรด
ytpillai

คำตอบ:


1417

เนื่องจากคำถามนี้ถูกถามในปี 2010 ได้มีการทำให้เข้าใจง่ายจริงในวิธีการทำมัลติเธรดที่เรียบง่ายกับงูหลามกับแผนที่และสระว่ายน้ำ

โค้ดข้างล่างนี้มาจากการโพสต์บทความ / บล็อกที่คุณแน่นอนควรตรวจสอบ (ไม่มีสังกัด) - ความเท่าเทียมในหนึ่งบรรทัด: รุ่นที่ดีกว่าสำหรับวันต่อวัน Threading งาน ฉันจะสรุปด้านล่าง - มันเป็นเพียงไม่กี่บรรทัดของรหัส:

from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(4)
results = pool.map(my_function, my_array)

เวอร์ชันมัลติเธรดของ:

results = []
for item in my_array:
    results.append(my_function(item))

ลักษณะ

แผนที่เป็นฟังก์ชั่นเล็ก ๆ น้อย ๆ ที่ยอดเยี่ยมและกุญแจสำคัญในการฉีดคู่ขนานลงในรหัส Python ของคุณได้อย่างง่ายดาย สำหรับสิ่งที่ไม่คุ้นเคยแผนที่นั้นเป็นสิ่งที่ยกมาจากภาษาที่ใช้งานได้เช่น Lisp มันเป็นฟังก์ชั่นที่แมปฟังก์ชั่นอื่นในลำดับ

แผนที่จัดการการวนซ้ำตามลำดับสำหรับเราใช้ฟังก์ชันและเก็บผลลัพธ์ทั้งหมดในรายการที่มีประโยชน์ในตอนท้าย

ป้อนคำอธิบายภาพที่นี่


การดำเนินงาน

ฟังก์ชันแผนที่รุ่นคู่ขนานมีให้โดยสองไลบรารี: การประมวลผลหลายตัวและยังเป็นที่รู้จักเพียงเล็กน้อย แต่เป็นขั้นตอนที่เด็ก ๆ น่าอัศจรรย์: multiprocessing.dummy

multiprocessing.dummyเหมือนกับโมดูลหลายตัวประมวลผลแต่ใช้เธรดแทน ( ความแตกต่างที่สำคัญ - ใช้หลายกระบวนการสำหรับงานที่ใช้ CPU มากเธรดสำหรับ (และระหว่าง) I / O ):

multiprocessing.dummy ทำซ้ำ API ของการประมวลผลหลายตัว แต่ไม่มากไปกว่า wrapper รอบ ๆ โมดูลเธรด

import urllib2
from multiprocessing.dummy import Pool as ThreadPool

urls = [
  'http://www.python.org',
  'http://www.python.org/about/',
  'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
  'http://www.python.org/doc/',
  'http://www.python.org/download/',
  'http://www.python.org/getit/',
  'http://www.python.org/community/',
  'https://wiki.python.org/moin/',
]

# Make the Pool of workers
pool = ThreadPool(4)

# Open the URLs in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)

# Close the pool and wait for the work to finish
pool.close()
pool.join()

และผลการจับเวลา:

Single thread:   14.4 seconds
       4 Pool:   3.1 seconds
       8 Pool:   1.4 seconds
      13 Pool:   1.3 seconds

ผ่านอาร์กิวเมนต์หลายตัว (ใช้งานได้เช่นนี้เฉพาะใน Python 3.3 และใหม่กว่า ):

ในการผ่านหลายอาร์เรย์:

results = pool.starmap(function, zip(list_a, list_b))

หรือผ่านค่าคงที่และอาร์เรย์:

results = pool.starmap(function, zip(itertools.repeat(constant), list_a))

หากคุณใช้ Python เวอร์ชันก่อนหน้าคุณสามารถส่งผ่านอาร์กิวเมนต์หลายตัวผ่านวิธีแก้ปัญหานี้ )

(ขอบคุณuser136036สำหรับความคิดเห็นที่เป็นประโยชน์)


90
นี่เป็นเพียงการขาดคะแนนเพราะมันโพสต์ใหม่ คำตอบนี้ใช้งานได้อย่างสวยงามและแสดงให้เห็นถึงฟังก์ชั่น 'แผนที่' ซึ่งจะทำให้เข้าใจไวยากรณ์ได้ง่ายกว่าคำตอบอื่น ๆ ที่นี่
ว่าง

25
สิ่งนี้เป็นเธรดและไม่ประมวลผลหรือไม่? ดูเหมือนว่าจะพยายามมัลติ
โพรเซสเซอร์

72
โดยวิธีการที่พวกคุณสามารถเขียนwith Pool(8) as p: p.map( *whatever* )และกำจัดสายการทำบัญชีเช่นกัน

11
@BarafuAlbino: มีประโยชน์อย่างที่ควรจะเป็นเพราะมันใช้งานได้ใน Python 3.3+เท่านั้น
fuglede

9
คุณจะออกจากคำตอบนี้ได้อย่างไรและไม่พูดถึงว่านี่เป็นประโยชน์สำหรับการดำเนินงาน I / O เท่านั้น? สิ่งนี้รันบนเธรดเดี่ยวซึ่งไม่มีประโยชน์สำหรับกรณีส่วนใหญ่และจริง ๆ แล้วช้ากว่าการทำตามปกติ
Frobot

714

นี่คือตัวอย่างง่ายๆ: คุณต้องลอง URL อื่นสองสามตัวและส่งคืนเนื้อหาของ URL แรกเพื่อตอบกลับ

import Queue
import threading
import urllib2

# Called by each thread
def get_url(q, url):
    q.put(urllib2.urlopen(url).read())

theurls = ["http://google.com", "http://yahoo.com"]

q = Queue.Queue()

for u in theurls:
    t = threading.Thread(target=get_url, args = (q,u))
    t.daemon = True
    t.start()

s = q.get()
print s

นี่เป็นกรณีที่การใช้เธรดเป็นการปรับให้เหมาะสมแบบง่าย: แต่ละเธรดย่อยกำลังรอให้ URL แก้ไขและตอบสนอง แต่ละเธรดเป็น daemon (จะไม่ทำให้กระบวนการทำงานหากเธรดหลักสิ้นสุด - ซึ่งเป็นเรื่องปกติมากกว่าไม่) เธรดหลักเริ่มเธรดย่อยทั้งหมดทำgetบนคิวเพื่อรอจนกระทั่งเธรดหนึ่งเสร็จputแล้วส่งผลลัพธ์และยุติ (ซึ่งจะลบเธรดย่อยใด ๆ ที่อาจยังทำงานอยู่เนื่องจากเธรด daemon)

การใช้เธรดใน Python อย่างเหมาะสมนั้นเชื่อมต่อกับการดำเนินการ I / O อย่างสม่ำเสมอ (เนื่องจาก CPython ไม่ได้ใช้หลายคอร์ในการรันงานที่ผูกกับ CPU อยู่แล้วเหตุผลเดียวที่เธรดไม่ได้บล็อกกระบวนการในขณะที่รอ I / O บางตัว ) คิวมักจะเป็นวิธีที่ดีที่สุดในการทำฟาร์มกับเธรดและ / หรือรวบรวมผลลัพธ์ของงานโดยวิธีการและพวกมันมีเธรดที่อยู่ในตัวดังนั้นพวกเขาจึงช่วยให้คุณไม่ต้องกังวลเกี่ยวกับล็อคเงื่อนไขกิจกรรมเซมาฟอร์และอื่น ๆ - แนวคิดการประสานงาน / การสื่อสารที่มีเธรด


10
ขอขอบคุณอีกครั้ง MartelliBot ฉันได้อัปเดตตัวอย่างเพื่อรอให้ทุกคนตอบกลับ: นำเข้าคิว, เธรด, urllib2 q = Queue.Queue () urls = '' a.com b.com c.com '' '. split () urls_received = 0 def get_url (q, url): req = urllib2.Request (url) resp = urllib2.urlopen (req) q.put (resp.read ()) urls_received urls_received + = 1 สำหรับ u ใน urls: t = threading.Thread (เป้าหมาย = get_url, args = (q, u)) t.daemon = True t.start () ขณะที่ q.empty () และ urls_received <len (urls): s = q.get () พิมพ์ s
htmldrum

3
@JRM: ถ้าคุณดูคำตอบต่อไปด้านล่างฉันคิดว่าวิธีที่ดีกว่าที่จะรอจนกว่ากระทู้เสร็จแล้วจะใช้join()วิธีการตั้งแต่ที่จะทำให้เธรดหลักรอจนกว่าพวกเขาจะทำโดยไม่ต้องใช้ตัวประมวลผลอย่างต่อเนื่อง ตรวจสอบค่า @Alex: ขอบคุณนี่เป็นสิ่งที่ฉันต้องการเพื่อทำความเข้าใจวิธีใช้เธรด
krs013

6
สำหรับ python3 ให้แทนที่ 'import urllib2' ด้วย 'import urllib.request as urllib2' และใส่วงเล็บในคำสั่งพิมพ์
ฮาร์วีย์

5
สำหรับหลาม 3 เปลี่ยนชื่อโมดูลด้วยQueue queueชื่อวิธีการเหมือนกัน
JSmyth

2
ฉันทราบว่าโซลูชันจะพิมพ์หน้าใดหน้าหนึ่งออกเท่านั้น หากต้องการพิมพ์ทั้งสองหน้าจากคิวเพียงรันคำสั่งอีกครั้ง: s = q.get() print s @ krs013 คุณไม่จำเป็นต้องใช้joinเพราะ Queue.get () กำลังปิดกั้น
Tom Anderson

256

หมายเหตุ : สำหรับการขนานที่เกิดขึ้นจริงใน Python คุณควรใช้โมดูลมัลติโพรเซสซิงเพื่อแยกกระบวนการหลายอย่างที่ดำเนินการแบบขนาน (เนื่องจากการล็อคล่ามทั่วโลก, เธรด Python จัดเตรียมการแทรกซึม แต่ในความเป็นจริงแล้ว มีประโยชน์เมื่อดำเนินการ I / O interleaving)

อย่างไรก็ตามหากคุณกำลังมองหา interleaving (หรือกำลังดำเนินการ I / O ที่สามารถขนานกันได้แม้จะมีการล็อคล่ามทั่วโลก) ดังนั้นโมดูลเธรดเป็นจุดเริ่มต้น เป็นตัวอย่างง่าย ๆ ลองพิจารณาปัญหาของการรวมช่วงขนาดใหญ่ด้วยการหาผลรวมของ subranges แบบขนาน:

import threading

class SummingThread(threading.Thread):
     def __init__(self,low,high):
         super(SummingThread, self).__init__()
         self.low=low
         self.high=high
         self.total=0

     def run(self):
         for i in range(self.low,self.high):
             self.total+=i


thread1 = SummingThread(0,500000)
thread2 = SummingThread(500000,1000000)
thread1.start() # This actually causes the thread to run
thread2.start()
thread1.join()  # This waits until the thread has completed
thread2.join()
# At this point, both threads have completed
result = thread1.total + thread2.total
print result

โปรดทราบว่าข้างต้นเป็นตัวอย่างที่โง่มากเพราะมันไม่มี I / O อย่างแน่นอนและจะถูกดำเนินการตามลำดับแม้ว่าจะมีการแทรกแบบอินเตอร์แอคทีฟ (ด้วยการเพิ่มการสลับบริบท) ในCPythonเนื่องจากการล็อคล่ามทั่วโลก


16
@ อเล็กซ์ฉันไม่ได้บอกว่ามันใช้งานได้จริง แต่มันแสดงให้เห็นถึงวิธีการกำหนดและวางไข่กระทู้ซึ่งฉันคิดว่าเป็นสิ่งที่ OP ต้องการ
Michael Aaron Safyan

6
ขณะนี้แสดงวิธีการกำหนดและวางไข่เธรดจริง ๆ แล้วมันไม่รวม subranges ในแบบขนาน thread1ทำงานจนกว่าจะเสร็จสมบูรณ์ในขณะที่บล็อกเธรดหลักจากนั้นเกิดสิ่งเดียวกันกับthread2จากนั้นเธรดหลักจะดำเนินการต่อและพิมพ์ค่าที่สะสม
martineau

ไม่ควรจะเป็นอย่างนั้นsuper(SummingThread, self).__init__()? ในstackoverflow.com/a/2197625/806988
James Andres

@JamesAndres สมมติว่าไม่มีใครสืบทอดจาก "SummingThread" จากนั้นทั้งคู่ก็ทำงานได้ดี ในกรณีเช่นนี้ super (SummingThread, self) เป็นเพียงวิธีแฟนซีในการค้นหาคลาสถัดไปในเมธอดการแก้ไขเมธอด (MRO) ซึ่งเป็นเธรดเธรด (จากนั้นจึงเรียกinitบนทั้งสองกรณี) คุณพูดถูกในการใช้ super () เป็นสไตล์ที่ดีกว่าสำหรับ Python ปัจจุบัน Super ค่อนข้างเร็ว ๆ นี้ในขณะที่ฉันตอบคำถามนี้ดังนั้นจึงโทรไปยัง super class โดยตรงแทนที่จะใช้ super () ฉันจะอัปเดตสิ่งนี้เพื่อใช้ super
Michael Aaron Safyan

14
คำเตือน: อย่าใช้งานมัลติเธรดในงานแบบนี้! ดังที่แสดงโดย Dave Beazley: dabeaz.com/python/NewGIL.pdf เธรด 2 ไพ ธ อนบน 2 ซีพียูทำงานหนักของซีพียู 2 ครั้งช้ากว่า 1 เธรดใน 1 ซีพียูและ 1.5 เท่าช้ากว่า 2 เธรดต่อ 1 ซีพียู พฤติกรรมที่แปลกประหลาดนี้เกิดจากการประสานงานระหว่าง OS และ Python อย่างไม่ถูกต้อง กรณีการใช้งานจริงสำหรับเธรดเป็นงานหนักของ I / O เช่นเมื่อคุณอ่าน / เขียนผ่านเครือข่ายคุณควรใส่เธรดรอข้อมูลที่จะอ่าน / เขียนเป็นพื้นหลังและสลับ CPU ไปยังเธรดอื่นซึ่งจำเป็นต้องประมวลผลข้อมูล
Boris Burkov

98

เช่นเดียวกับคนอื่น ๆ ที่กล่าวถึง CPython สามารถใช้เธรดเฉพาะสำหรับ I / O ที่รอเนื่องจากGIL GIL

หากคุณต้องการได้รับประโยชน์จากหลายคอร์สำหรับงานที่ผูกกับ CPU ให้ใช้มัลติโพรเซสเซอร์ :

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

33
คุณช่วยอธิบายสิ่งนี้ได้ไหม
pandita

5
@pandita: รหัสสร้างกระบวนการจากนั้นเริ่มต้น ดังนั้นตอนนี้มีสองสิ่งที่เกิดขึ้นพร้อมกัน: สายหลักของโปรแกรมและกระบวนการที่เริ่มต้นด้วยเป้าหมายfฟังก์ชั่น ในขณะเดียวกันโปรแกรมหลักก็รอให้กระบวนการออกจากjoinไปพร้อมกับมัน หากส่วนหลักเพิ่งออกจากกระบวนการย่อยอาจหรือไม่อาจทำงานจนเสร็จดังนั้นแนะนำให้ทำjoinเสมอ
johntellsall

1
คำตอบเพิ่มเติมที่มีmapฟังก์ชั่นอยู่ที่นี่: stackoverflow.com/a/28463266/2327328
philshem

2
@philshem ระวัง B / C ลิงค์ที่คุณโพสต์คือการใช้สระว่ายน้ำของหัวข้อ (ไม่ประมวลผล) เป็นที่กล่าวถึงนี่stackoverflow.com/questions/26432411/... อย่างไรก็ตามคำตอบนี้ใช้กระบวนการ ฉันใหม่สำหรับสิ่งนี้ แต่ดูเหมือนว่า (เนื่องจาก GIL) คุณจะได้รับประสิทธิภาพที่เพิ่มขึ้นในสถานการณ์เฉพาะเมื่อใช้มัลติเธรดใน Python อย่างไรก็ตามการใช้กลุ่มของกระบวนการสามารถใช้ประโยชน์จากตัวประมวลผลแบบมัลติคอร์โดยมีมากกว่า 1 คอร์ทำงานในกระบวนการ
user3731622

3
นี่เป็นคำตอบที่ดีที่สุดสำหรับการทำสิ่งที่มีประโยชน์และใช้ประโยชน์จากคอร์ CPU หลายตัว
Frobot

92

เพียงทราบ: ไม่จำเป็นต้องมีคิวในการทำเกลียว

นี่คือตัวอย่างที่ง่ายที่สุดที่ผมสามารถจินตนาการได้แสดงให้เห็นว่า 10 กระบวนการทำงานควบคู่กันไป

import threading
from random import randint
from time import sleep


def print_number(number):

    # Sleeps a random 1 to 10 seconds
    rand_int_var = randint(1, 10)
    sleep(rand_int_var)
    print "Thread " + str(number) + " slept for " + str(rand_int_var) + " seconds"

thread_list = []

for i in range(1, 10):

    # Instantiates the thread
    # (i) does not make a sequence, so (i,)
    t = threading.Thread(target=print_number, args=(i,))
    # Sticks the thread in a list so that it remains accessible
    thread_list.append(t)

# Starts threads
for thread in thread_list:
    thread.start()

# This blocks the calling thread until the thread whose join() method is called is terminated.
# From http://docs.python.org/2/library/threading.html#thread-objects
for thread in thread_list:
    thread.join()

# Demonstrates that the main process waited for threads to complete
print "Done"

3
เพิ่มเครื่องหมายคำพูดสุดท้ายลงใน "เสร็จสิ้นเพื่อพิมพ์" เสร็จสิ้น "
iChux

1
ฉันชอบตัวอย่างนี้ดีกว่าของ Martelli ง่ายต่อการเล่นด้วย อย่างไรก็ตามฉันขอแนะนำให้ printNumber ทำสิ่งต่อไปนี้เพื่อให้ชัดเจนยิ่งขึ้นว่าเกิดอะไรขึ้น: ควรบันทึก randint เป็นตัวแปรก่อนที่จะนอนบนมันจากนั้นพิมพ์ควรเปลี่ยนเป็น "Thread" + str ( หมายเลข) + "นอนสำหรับ" + theRandintVariable + "วินาที"
นิโคไล

มีวิธีที่จะรู้ว่าเมื่อแต่ละกระทู้เสร็จสิ้นเมื่อมันเสร็จสิ้น?
Matt

1
@ แมทมีหลายวิธีที่จะทำสิ่งนั้น แต่มันก็ขึ้นอยู่กับความต้องการของคุณ วิธีหนึ่งคือการอัปเดตซิงเกิลหรือตัวแปรสาธารณะอื่น ๆ ที่สามารถดูได้ในขณะที่ลูปและอัปเดตที่ส่วนท้ายของเธรด
Douglas Adams

2
ไม่ต้องการวินาที forลูปคุณสามารถโทรthread.start()ในลูปแรก
Mark Mishyn

49

คำตอบจาก Alex Martelliช่วยฉัน อย่างไรก็ตามนี่เป็นรุ่นที่แก้ไขซึ่งฉันคิดว่ามีประโยชน์มากกว่า (อย่างน้อยสำหรับฉัน)

อัปเดต: ใช้งานได้ทั้ง Python 2 และ Python 3

try:
    # For Python 3
    import queue
    from urllib.request import urlopen
except:
    # For Python 2 
    import Queue as queue
    from urllib2 import urlopen

import threading

worker_data = ['http://google.com', 'http://yahoo.com', 'http://bing.com']

# Load up a queue with your data. This will handle locking
q = queue.Queue()
for url in worker_data:
    q.put(url)

# Define a worker function
def worker(url_queue):
    queue_full = True
    while queue_full:
        try:
            # Get your data off the queue, and do some work
            url = url_queue.get(False)
            data = urlopen(url).read()
            print(len(data))

        except queue.Empty:
            queue_full = False

# Create as many threads as you want
thread_count = 5
for i in range(thread_count):
    t = threading.Thread(target=worker, args = (q,))
    t.start()

6
ทำไมไม่ลองผิดลองดูล่ะ
Stavros Korokithakis

1
คุณทำได้เพียงตั้งค่าส่วนตัว
JimJty

1
ฉันไม่ได้เรียกใช้รหัส แต่คุณไม่จำเป็นต้อง daemonize เธรด? ฉันคิดว่าหลังจากนั้น for-loop ครั้งล่าสุดโปรแกรมของคุณอาจออก - อย่างน้อยก็ควรเป็นเพราะนั่นเป็นวิธีที่เธรดควรทำงาน ฉันคิดว่าวิธีที่ดีกว่านั้นไม่ได้ใส่ข้อมูลของคนงานในคิว แต่ใส่ผลลัพธ์ลงในคิวเพราะคุณสามารถมี mainloop ที่ไม่เพียง แต่จัดการข้อมูลที่เข้ามาในคิวจากคนงาน แต่ตอนนี้มันยังไม่เกลียว และคุณรู้ว่ามันจะไม่ออกก่อนเวลาอันควร
dylnmc

1
@dylnmc นั่นไม่ใช่กรณีการใช้งานของฉัน หากคุณต้องการไปตามเส้นทางของคุณฉันขอแนะนำให้ดูคื่นฉ่าย
JimJty

@JimJty คุณรู้ไหมว่าทำไมฉันถึงได้รับข้อผิดพลาดนี้: import Queue ModuleNotFoundError: No module named 'Queue'ฉันใช้ python 3.6.5 บางโพสต์พูดถึงว่าใน python 3.6.5 มันเป็นqueueแต่หลังจากที่ฉันเปลี่ยนมันยังคงไม่ทำงาน
user9371654

25

รับฟังก์ชั่นf, ด้ายมันเช่นนี้:

import threading
threading.Thread(target=f).start()

เพื่อส่งผ่านข้อโต้แย้งไปยัง f

threading.Thread(target=f, args=(a,b,c)).start()

ตรงไปตรงมามาก คุณจะมั่นใจได้อย่างไรว่าเธรดจะปิดเมื่อคุณทำเสร็จแล้ว?
cameronroytaylor

เท่าที่ฉันเข้าใจมันเมื่อฟังก์ชั่นออกจากThreadวัตถุทำความสะอาด ดูเอกสาร มีis_alive()วิธีที่คุณสามารถใช้เพื่อตรวจสอบเธรดถ้าคุณต้องการ
starfry

ฉันเห็นis_aliveวิธีการนี้ แต่ฉันไม่สามารถหาวิธีนำไปใช้กับเธรดได้ ฉันลองกำหนดthread1=threading.Thread(target=f).start()แล้วตรวจสอบด้วยthread1.is_alive()แต่thread1มีประชากรNoneดังนั้นจึงไม่มีโชค คุณรู้หรือไม่ว่ามีวิธีอื่นในการเข้าถึงเธรดหรือไม่
cameronroytaylor

4
คุณต้องกำหนดวัตถุด้ายให้กับตัวแปรและจะเริ่มต้นโดยใช้ varaible ว่าตามมาด้วยthread1=threading.Thread(target=f) จากนั้นคุณสามารถทำได้thread1.start() thread1.is_alive()
starfry

1
ที่ได้ผล และใช่การทดสอบโดยthread1.is_alive()ส่งคืนFalseทันทีที่ฟังก์ชันออก
cameronroytaylor

25

ฉันพบสิ่งนี้มีประโยชน์มาก: สร้างเธรดให้มากที่สุดเท่าที่แกนและให้พวกเขาดำเนินงานจำนวนมาก (ในกรณีนี้เรียกโปรแกรมเชลล์):

import Queue
import threading
import multiprocessing
import subprocess

q = Queue.Queue()
for i in range(30): # Put 30 tasks in the queue
    q.put(i)

def worker():
    while True:
        item = q.get()
        # Execute a task: call a shell program and wait until it completes
        subprocess.call("echo " + str(item), shell=True)
        q.task_done()

cpus = multiprocessing.cpu_count() # Detect number of cores
print("Creating %d threads" % cpus)
for i in range(cpus):
     t = threading.Thread(target=worker)
     t.daemon = True
     t.start()

q.join() # Block until all tasks are done

@shavenwarthog แน่ใจว่าสามารถปรับตัวแปร "cpus" ได้ตามความต้องการ อย่างไรก็ตามการเรียกกระบวนการย่อยจะวางไข่กระบวนการย่อยและสิ่งเหล่านี้จะได้รับการจัดสรรซีพียูโดยระบบปฏิบัติการ ("กระบวนการแม่" ของ python ไม่ได้หมายถึง "CPU เดียวกัน" สำหรับกระบวนการย่อย)
ปลาโลมา

2
คุณถูกต้องความคิดเห็นของฉันเกี่ยวกับ "กระทู้เริ่มต้นบน CPU เดียวกันกับกระบวนการหลัก" ผิด ขอบคุณสำหรับการตอบกลับ!
johntellsall

1
อาจจะน่าสังเกตว่าไม่เหมือนมัลติเธรดซึ่งใช้พื้นที่หน่วยความจำเดียวกันการประมวลผลหลายตัวไม่สามารถแชร์ตัวแปร / ข้อมูลได้อย่างง่ายดาย +1 แม้ว่า
เพ้อฝัน

22

Python 3 มีสิ่งอำนวยความสะดวกในการเรียกใช้งานแบบคู่ขนานการเปิดตัวงานคู่ขนานนี่ทำให้งานของเราง่ายขึ้น

มันมีเธรดร่วมกันและกระบวนการรวมกำไรกระบวนการร่วมกัน

ต่อไปนี้จะให้ข้อมูลเชิงลึก:

ตัวอย่าง ThreadPoolExecutor ( ต้นฉบับ )

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

ProcessPoolExecutor ( แหล่งที่มา )

import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()

18

การใช้โมดูลconcurrent.futuresใหม่ที่เห็นได้ชัด

def sqr(val):
    import time
    time.sleep(0.1)
    return val * val

def process_result(result):
    print(result)

def process_these_asap(tasks):
    import concurrent.futures

    with concurrent.futures.ProcessPoolExecutor() as executor:
        futures = []
        for task in tasks:
            futures.append(executor.submit(sqr, task))

        for future in concurrent.futures.as_completed(futures):
            process_result(future.result())
        # Or instead of all this just do:
        # results = executor.map(sqr, tasks)
        # list(map(process_result, results))

def main():
    tasks = list(range(10))
    print('Processing {} tasks'.format(len(tasks)))
    process_these_asap(tasks)
    print('Done')
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main())

วิธีการของผู้ปฏิบัติการอาจดูเหมือนคุ้นเคยกับทุกคนที่เคยชินกับมือที่สกปรกกับ Java มาก่อน

ข้อสังเกตด้านข้าง: เพื่อรักษาความมีสติของจักรวาลอย่าลืมปิด pool / executors ของคุณหากคุณไม่ใช้withบริบท


17

สำหรับฉันตัวอย่างที่สมบูรณ์แบบสำหรับการทำเกลียวคือการตรวจสอบเหตุการณ์ไม่ตรงกัน ดูรหัสนี้

# thread_test.py
import threading
import time

class Monitor(threading.Thread):
    def __init__(self, mon):
        threading.Thread.__init__(self)
        self.mon = mon

    def run(self):
        while True:
            if self.mon[0] == 2:
                print "Mon = 2"
                self.mon[0] = 3;

คุณสามารถเล่นกับรหัสนี้โดยเปิดเซสชันIPythonและทำสิ่งที่ชอบ:

>>> from thread_test import Monitor
>>> a = [0]
>>> mon = Monitor(a)
>>> mon.start()
>>> a[0] = 2
Mon = 2
>>>a[0] = 2
Mon = 2

รอสักครู่

>>> a[0] = 2
Mon = 2

1
AttributeError: วัตถุ 'ตรวจสอบ' ไม่มีแอตทริบิวต์ 'หยุด'?
pandita

5
คุณไม่ทำลายซีพียูในขณะที่รอให้เหตุการณ์เกิดขึ้นหรือไม่ ไม่ใช่สิ่งที่ต้องปฏิบัติจริง ๆ เสมอไป
เจ้าพ่อ

3
เช่นเดียวกับเจ้าพ่อกล่าวว่าสิ่งนี้จะดำเนินการอย่างต่อเนื่อง อย่างน้อยที่สุดคุณก็สามารถเพิ่มในโหมดสลีปสั้น ๆ พูดโหมด sleep (0.1) ซึ่งอาจลดการใช้ cpu ลงอย่างมากในตัวอย่างง่ายๆเช่นนี้
เพ้อฝัน

3
นี่คือตัวอย่างที่น่ากลัวเสียหนึ่งหลัก เพิ่มโหมดสลีปอย่างน้อยที่สุด แต่วิธีแก้ปัญหาที่เหมาะสมคือใช้กลไกการส่งสัญญาณ
PureW

16

เอกสารและแบบฝึกหัดส่วนใหญ่ใช้ Python ThreadingและQueueโมดูลและพวกเขาอาจดูล้นหลามสำหรับผู้เริ่มต้น

อาจพิจารณา concurrent.futures.ThreadPoolExecutorโมดูลของ Python 3

เมื่อรวมกับwithข้อและรายการความเข้าใจมันอาจเป็นเสน่ห์ที่แท้จริง

from concurrent.futures import ThreadPoolExecutor, as_completed

def get_url(url):
    # Your actual program here. Using threading.Lock() if necessary
    return ""

# List of URLs to fetch
urls = ["url1", "url2"]

with ThreadPoolExecutor(max_workers = 5) as executor:

    # Create threads
    futures = {executor.submit(get_url, url) for url in urls}

    # as_completed() gives you the threads once finished
    for f in as_completed(futures):
        # Get the results
        rs = f.result()

15

ฉันเห็นตัวอย่างมากมายที่นี่ที่ไม่มีการทำงานจริงและพวกเขาส่วนใหญ่เป็น CPU-bound นี่คือตัวอย่างของภาระผูกพันของ CPU ที่คำนวณจำนวนเฉพาะทั้งหมดระหว่าง 10 ล้านถึง 10.05 ล้าน ฉันใช้ทั้งสี่วิธีที่นี่:

import math
import timeit
import threading
import multiprocessing
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor


def time_stuff(fn):
    """
    Measure time of execution of a function
    """
    def wrapper(*args, **kwargs):
        t0 = timeit.default_timer()
        fn(*args, **kwargs)
        t1 = timeit.default_timer()
        print("{} seconds".format(t1 - t0))
    return wrapper

def find_primes_in(nmin, nmax):
    """
    Compute a list of prime numbers between the given minimum and maximum arguments
    """
    primes = []

    # Loop from minimum to maximum
    for current in range(nmin, nmax + 1):

        # Take the square root of the current number
        sqrt_n = int(math.sqrt(current))
        found = False

        # Check if the any number from 2 to the square root + 1 divides the current numnber under consideration
        for number in range(2, sqrt_n + 1):

            # If divisible we have found a factor, hence this is not a prime number, lets move to the next one
            if current % number == 0:
                found = True
                break

        # If not divisible, add this number to the list of primes that we have found so far
        if not found:
            primes.append(current)

    # I am merely printing the length of the array containing all the primes, but feel free to do what you want
    print(len(primes))

@time_stuff
def sequential_prime_finder(nmin, nmax):
    """
    Use the main process and main thread to compute everything in this case
    """
    find_primes_in(nmin, nmax)

@time_stuff
def threading_prime_finder(nmin, nmax):
    """
    If the minimum is 1000 and the maximum is 2000 and we have four workers,
    1000 - 1250 to worker 1
    1250 - 1500 to worker 2
    1500 - 1750 to worker 3
    1750 - 2000 to worker 4
    so let’s split the minimum and maximum values according to the number of workers
    """
    nrange = nmax - nmin
    threads = []
    for i in range(8):
        start = int(nmin + i * nrange/8)
        end = int(nmin + (i + 1) * nrange/8)

        # Start the thread with the minimum and maximum split up to compute
        # Parallel computation will not work here due to the GIL since this is a CPU-bound task
        t = threading.Thread(target = find_primes_in, args = (start, end))
        threads.append(t)
        t.start()

    # Don’t forget to wait for the threads to finish
    for t in threads:
        t.join()

@time_stuff
def processing_prime_finder(nmin, nmax):
    """
    Split the minimum, maximum interval similar to the threading method above, but use processes this time
    """
    nrange = nmax - nmin
    processes = []
    for i in range(8):
        start = int(nmin + i * nrange/8)
        end = int(nmin + (i + 1) * nrange/8)
        p = multiprocessing.Process(target = find_primes_in, args = (start, end))
        processes.append(p)
        p.start()

    for p in processes:
        p.join()

@time_stuff
def thread_executor_prime_finder(nmin, nmax):
    """
    Split the min max interval similar to the threading method, but use a thread pool executor this time.
    This method is slightly faster than using pure threading as the pools manage threads more efficiently.
    This method is still slow due to the GIL limitations since we are doing a CPU-bound task.
    """
    nrange = nmax - nmin
    with ThreadPoolExecutor(max_workers = 8) as e:
        for i in range(8):
            start = int(nmin + i * nrange/8)
            end = int(nmin + (i + 1) * nrange/8)
            e.submit(find_primes_in, start, end)

@time_stuff
def process_executor_prime_finder(nmin, nmax):
    """
    Split the min max interval similar to the threading method, but use the process pool executor.
    This is the fastest method recorded so far as it manages process efficiently + overcomes GIL limitations.
    RECOMMENDED METHOD FOR CPU-BOUND TASKS
    """
    nrange = nmax - nmin
    with ProcessPoolExecutor(max_workers = 8) as e:
        for i in range(8):
            start = int(nmin + i * nrange/8)
            end = int(nmin + (i + 1) * nrange/8)
            e.submit(find_primes_in, start, end)

def main():
    nmin = int(1e7)
    nmax = int(1.05e7)
    print("Sequential Prime Finder Starting")
    sequential_prime_finder(nmin, nmax)
    print("Threading Prime Finder Starting")
    threading_prime_finder(nmin, nmax)
    print("Processing Prime Finder Starting")
    processing_prime_finder(nmin, nmax)
    print("Thread Executor Prime Finder Starting")
    thread_executor_prime_finder(nmin, nmax)
    print("Process Executor Finder Starting")
    process_executor_prime_finder(nmin, nmax)

main()

นี่คือผลลัพธ์บนเครื่องสี่หลักของ Mac OS X ของฉัน

Sequential Prime Finder Starting
9.708213827005238 seconds
Threading Prime Finder Starting
9.81836523200036 seconds
Processing Prime Finder Starting
3.2467174359990167 seconds
Thread Executor Prime Finder Starting
10.228896902000997 seconds
Process Executor Finder Starting
2.656402041000547 seconds

1
@ TheUnfunCat ไม่มีผู้ดำเนินการในกระบวนการที่ดีกว่าเธรดสำหรับงานที่ถูกผูกไว้กับ cpu
PirateApp

1
คำตอบที่ดีครับ ฉันสามารถยืนยันได้ว่าใน Python 3.6 บน Windows (อย่างน้อย) ThreadPoolExecutor ไม่ได้ทำอะไรที่ดีสำหรับงานที่มี CPU มาก มันไม่ได้ใช้ประโยชน์จากแกนสำหรับการคำนวณ ในขณะที่ ProcessPoolExecutor คัดลอกข้อมูลไปยังกระบวนการทุก ๆ ครั้งมันวางไข่มันร้ายแรงสำหรับเมทริกซ์ขนาดใหญ่
Anatoly Alekseev

1
ตัวอย่างที่มีประโยชน์มาก แต่ฉันไม่เข้าใจว่ามันทำงานอย่างไร เราจำเป็นต้องมีif __name__ == '__main__':ก่อนที่จะสายหลักมิฉะนั้น spawns วัดตัวเองและภาพพิมพ์มีความพยายามที่ได้ทำเพื่อเริ่มต้นกระบวนการใหม่ก่อน ...
สไตน์

1
@ สเตนฉันเชื่อว่านี่เป็นเพียงปัญหาของ Windows เท่านั้น
AMC

12

นี่คือตัวอย่างง่ายๆของCSVการนำเข้าโดยใช้เธรด (การรวมห้องสมุดอาจแตกต่างกันเพื่อวัตถุประสงค์ที่แตกต่างกัน)

ฟังก์ชั่นผู้ช่วย:

from threading import Thread
from project import app
import csv


def import_handler(csv_file_name):
    thr = Thread(target=dump_async_csv_data, args=[csv_file_name])
    thr.start()

def dump_async_csv_data(csv_file_name):
    with app.app_context():
        with open(csv_file_name) as File:
            reader = csv.DictReader(File)
            for row in reader:
                # DB operation/query

ฟังก์ชั่นไดร์เวอร์:

import_handler(csv_file_name)

9

ฉันต้องการมีส่วนร่วมกับตัวอย่างง่ายๆและคำอธิบายที่ฉันพบว่ามีประโยชน์เมื่อฉันต้องจัดการปัญหานี้ด้วยตัวเอง

ในคำตอบนี้คุณจะพบข้อมูลบางอย่างเกี่ยวกับGILของ Python (ล็อคล่ามทั่วโลก) และตัวอย่างง่าย ๆ แบบวันต่อวันที่เขียนโดยใช้การประมวลผลแบบมัลติโพรเซสซิง

Global Interpreter Lock (GIL)

Python ไม่อนุญาตให้มีหลายเธรดในความหมายที่แท้จริงของคำ มันมีแพ็คเกจแบบมัลติเธรด แต่ถ้าคุณต้องการมัลติเธรดเพื่อเพิ่มความเร็วรหัสของคุณก็มักจะไม่ควรใช้มัน

Python มีโครงสร้างที่เรียกว่า global interpreter lock (GIL) GIL ทำให้แน่ใจว่ามีเพียงหนึ่งใน 'กระทู้' ของคุณเท่านั้นที่สามารถดำเนินการได้ในคราวเดียว เธรดรับ GIL, ทำงานเล็กน้อยแล้วส่ง GIL ไปยังเธรดถัดไป

สิ่งนี้เกิดขึ้นได้อย่างรวดเร็วดังนั้นในสายตามนุษย์อาจดูเหมือนว่าเธรดของคุณกำลังดำเนินการแบบขนาน

การผ่าน GIL ​​ทั้งหมดนี้เพิ่มค่าใช้จ่ายในการดำเนินการ ซึ่งหมายความว่าหากคุณต้องการทำให้โค้ดของคุณทำงานได้เร็วขึ้นการใช้เธรดแพ็คเกจมักจะไม่ใช่ความคิดที่ดี

มีเหตุผลที่จะใช้ชุดเธรดของ Python หากคุณต้องการดำเนินการบางอย่างพร้อมกันและประสิทธิภาพไม่ใช่เรื่องที่กังวลเลยมันดีและสะดวกมาก หรือถ้าคุณกำลังเรียกใช้รหัสที่ต้องรอบางสิ่ง (เช่น I / O บางอย่าง) มันอาจสมเหตุสมผลดี แต่ไลบรารีเธรดจะไม่ยอมให้คุณใช้คอร์ CPU เพิ่มเติม

มัลติเธรดสามารถเอาต์ซอร์ซไปยังระบบปฏิบัติการ (โดยทำการประมวลผลหลายอย่าง) และแอปพลิเคชั่นภายนอกบางอย่างที่เรียกรหัส Python ของคุณ (เช่นSparkหรือHadoop ) หรือรหัสบางอย่างที่รหัส Python ของคุณโทร (เช่น: ให้รหัสไพ ธ อนของคุณเรียกใช้ฟังก์ชัน C ซึ่งทำสิ่งที่มีหลายเธรดราคาแพง)

ทำไมเรื่องนี้

เพราะผู้คนจำนวนมากใช้เวลามากมายในการหาคอขวดในรหัส Python แบบมัลติเธรดแฟนซีของพวกเขาก่อนที่พวกเขาจะเรียนรู้ว่า GIL คืออะไร

เมื่อข้อมูลนี้ชัดเจนแล้วนี่คือรหัสของฉัน:

#!/bin/python
from multiprocessing.dummy import Pool
from subprocess import PIPE,Popen
import time
import os

# In the variable pool_size we define the "parallelness".
# For CPU-bound tasks, it doesn't make sense to create more Pool processes
# than you have cores to run them on.
#
# On the other hand, if you are using I/O-bound tasks, it may make sense
# to create a quite a few more Pool processes than cores, since the processes
# will probably spend most their time blocked (waiting for I/O to complete).
pool_size = 8

def do_ping(ip):
    if os.name == 'nt':
        print ("Using Windows Ping to " + ip)
        proc = Popen(['ping', ip], stdout=PIPE)
        return proc.communicate()[0]
    else:
        print ("Using Linux / Unix Ping to " + ip)
        proc = Popen(['ping', ip, '-c', '4'], stdout=PIPE)
        return proc.communicate()[0]


os.system('cls' if os.name=='nt' else 'clear')
print ("Running using threads\n")
start_time = time.time()
pool = Pool(pool_size)
website_names = ["www.google.com","www.facebook.com","www.pinterest.com","www.microsoft.com"]
result = {}
for website_name in website_names:
    result[website_name] = pool.apply_async(do_ping, args=(website_name,))
pool.close()
pool.join()
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))

# Now we do the same without threading, just to compare time
print ("\nRunning NOT using threads\n")
start_time = time.time()
for website_name in website_names:
    do_ping(website_name)
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))

# Here's one way to print the final output from the threads
output = {}
for key, value in result.items():
    output[key] = value.get()
print ("\nOutput aggregated in a Dictionary:")
print (output)
print ("\n")

print ("\nPretty printed output: ")
for key, value in output.items():
    print (key + "\n")
    print (value)

7

นี่คือหลายเธรดด้วยตัวอย่างง่าย ๆ ซึ่งจะเป็นประโยชน์ คุณสามารถรันและเข้าใจได้ง่ายว่ามัลติเธรดทำงานอย่างไรใน Python ฉันใช้ล็อกเพื่อป้องกันการเข้าถึงเธรดอื่น ๆ จนกว่าเธรดก่อนหน้านี้จะทำงานเสร็จ โดยการใช้รหัสบรรทัดนี้

tLock = threading.BoundedSemaphore (ค่า = 4)

คุณสามารถอนุญาตให้กระบวนการจำนวนมากในแต่ละครั้งและเก็บไว้ที่ส่วนที่เหลือของกระทู้ซึ่งจะทำงานในภายหลังหรือหลังจากกระบวนการก่อนหน้านี้เสร็จสิ้น

import threading
import time

#tLock = threading.Lock()
tLock = threading.BoundedSemaphore(value=4)
def timer(name, delay, repeat):
    print  "\r\nTimer: ", name, " Started"
    tLock.acquire()
    print "\r\n", name, " has the acquired the lock"
    while repeat > 0:
        time.sleep(delay)
        print "\r\n", name, ": ", str(time.ctime(time.time()))
        repeat -= 1

    print "\r\n", name, " is releaseing the lock"
    tLock.release()
    print "\r\nTimer: ", name, " Completed"

def Main():
    t1 = threading.Thread(target=timer, args=("Timer1", 2, 5))
    t2 = threading.Thread(target=timer, args=("Timer2", 3, 5))
    t3 = threading.Thread(target=timer, args=("Timer3", 4, 5))
    t4 = threading.Thread(target=timer, args=("Timer4", 5, 5))
    t5 = threading.Thread(target=timer, args=("Timer5", 0.1, 5))

    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t5.start()

    print "\r\nMain Complete"

if __name__ == "__main__":
    Main()

5

ด้วยการยืมจากโพสต์นี้เรารู้เกี่ยวกับการเลือกระหว่างการทำมัลติเธรดการมัลติโพรเซสเซอร์และ async / asyncioและการใช้งาน

Python 3มีไลบรารีในตัวใหม่เพื่อการทำงานพร้อมกันและการขนาน: concurrent.futures

ดังนั้นฉันจะแสดงให้เห็นถึงการทดสอบเพื่อให้ทำงานสี่อย่าง (เช่น.sleep()วิธีการ) ตามThreading-Poolลักษณะ:

from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep, time

def concurrent(max_worker=1):
    futures = []

    tick = time()
    with ThreadPoolExecutor(max_workers=max_worker) as executor:
        futures.append(executor.submit(sleep, 2))  # Two seconds sleep
        futures.append(executor.submit(sleep, 1))
        futures.append(executor.submit(sleep, 7))
        futures.append(executor.submit(sleep, 3))

        for future in as_completed(futures):
            if future.result() is not None:
                print(future.result())

    print('Total elapsed time by {} workers:'.format(max_worker), time()-tick)

concurrent(5)
concurrent(4)
concurrent(3)
concurrent(2)
concurrent(1)

เอาท์พุท:

Total elapsed time by 5 workers: 7.007831811904907
Total elapsed time by 4 workers: 7.007944107055664
Total elapsed time by 3 workers: 7.003149509429932
Total elapsed time by 2 workers: 8.004627466201782
Total elapsed time by 1 workers: 13.013478994369507

[ หมายเหตุ ]:

  • อย่างที่คุณเห็นในผลลัพธ์ข้างต้นกรณีที่ดีที่สุดคือ3คนสำหรับงานทั้งสี่นั้น
  • ถ้าคุณมีงานกระบวนการแทน I / O ผูกพันหรือการปิดกั้น ( multiprocessingVS threading) คุณอาจจะเปลี่ยนไปThreadPoolExecutorProcessPoolExecutor

4

ไม่มีวิธีการก่อนหน้านี้ที่ใช้หลายคอร์จริง ๆ บนเซิร์ฟเวอร์ GNU / Linux ของฉัน (ที่ฉันไม่มีสิทธิ์ของผู้ดูแลระบบ) พวกเขาวิ่งบนแกนเดียว

ฉันใช้os.forkอินเทอร์เฟซระดับต่ำกว่าเพื่อวางไข่หลายกระบวนการ นี่คือรหัสที่ใช้งานได้สำหรับฉัน:

from os import fork

values = ['different', 'values', 'for', 'threads']

for i in range(len(values)):
    p = fork()
    if p == 0:
        my_function(values[i])
        break

2
import threading
import requests

def send():

  r = requests.get('https://www.stackoverlow.com')

thread = []
t = threading.Thread(target=send())
thread.append(t)
t.start()

1
@sP_ ฉันคาดเดาเพราะคุณมีวัตถุเธรดเพื่อให้คุณรอให้เสร็จ
Aleksandar Makragić

1
t = เธรดเธรด (target = send ()) ควรเป็น t = เธรดเธรด (target = send)
TRiNE

ฉันกำลัง downvoting คำตอบนี้เพราะมันไม่ได้ให้คำอธิบายว่าจะปรับปรุงอย่างไรกับคำตอบที่มีอยู่นอกเหนือจากการมีความไม่ถูกต้องที่ร้ายแรง
จูลส์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.