asyncio.ensure_future বনাম। বেসএভেন্টলুপ ক্রেইট_টাস্ক বনাম সহজ সরকারী?


101

অ্যাসিনসিওর বিভিন্ন স্বাদে একই অপারেশন করতে আমি বেশ কয়েকটি বেসিক পাইথন 3.5 টি টিউটোরিয়াল দেখেছি। এই কোডে:

import asyncio  

async def doit(i):
    print("Start %d" % i)
    await asyncio.sleep(3)
    print("End %d" % i)
    return i

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    #futures = [asyncio.ensure_future(doit(i), loop=loop) for i in range(10)]
    #futures = [loop.create_task(doit(i)) for i in range(10)]
    futures = [doit(i) for i in range(10)]
    result = loop.run_until_complete(asyncio.gather(*futures))
    print(result)

উপরের তিনটি বৈকল্পিক যা futuresভেরিয়েবলকে একই ফলাফল অর্জনের সংজ্ঞা দেয় ; কেবলমাত্র তফাতটি আমি দেখতে পাচ্ছি তা হ'ল তৃতীয় বৈকল্পিকের সাথে মৃত্যুদন্ড কার্যকর করা কার্যকর নয় (যা বেশিরভাগ ক্ষেত্রে কার্যকর হওয়া উচিত নয়)। অন্য কোন পার্থক্য আছে? এমন কিছু ঘটনা আছে যেখানে আমি কেবল সহজতম রূপটি ব্যবহার করতে পারি না (কর্টিনগুলির সরল তালিকা)?

উত্তর:


121

আসল তথ্য:

পাইথন থেকে শুরু করে asyncio.create_task(coro)উচ্চ-স্তরের ফাংশন এই উদ্দেশ্যে যুক্ত করা হয়েছিল

আপনার এটির পরিবর্তে কর্যুর সময় থেকে কাজগুলি তৈরি করার অন্যান্য উপায়গুলি ব্যবহার করা উচিত। তবে আপনার যদি স্বেচ্ছাসেবী থেকে প্রত্যাশিত থেকে কোনও কাজ তৈরি করতে হয় তবে আপনার ব্যবহার করা উচিত asyncio.ensure_future(obj)


পুরানো তথ্য:

ensure_future বনাম create_task

ensure_futureTaskথেকে তৈরি একটি পদ্ধতি coroutine। এটি আর্গুমেন্টের উপর ভিত্তি করে বিভিন্ন ধরণের টাস্ক তৈরি করে ( create_taskকর্টাইন এবং ভবিষ্যতের মতো সামগ্রীর জন্য ব্যবহার সহ )।

create_taskএর একটি বিমূর্ত পদ্ধতি AbstractEventLoop। বিভিন্ন ইভেন্টের লুপগুলি এই কার্যটি বিভিন্ন উপায়ে বাস্তবায়ন করতে পারে।

ensure_futureকাজগুলি তৈরি করতে আপনার ব্যবহার করা উচিত । আপনি create_taskকেবল নিজের ইভেন্ট লুপের প্রকারটি প্রয়োগ করতে গেলে আপনার প্রয়োজন হবে ।

আপডেট:

@ bj0 দিকে তাক গাইডো এর উত্তর এই বিষয়ে:

মূল ensure_future()বক্তব্যটি হ'ল যদি আপনার কাছে এমন কিছু থাকে যা হয় হয় কর্টিন বা একটি হতে পারে Future(এর মধ্যে একটি Taskকারণ এটি একটি সাবক্লাস রয়েছে Future), এবং আপনি এটিতে কোনও পদ্ধতিতে কল করতে সক্ষম হতে চান যা কেবলমাত্র সংজ্ঞায়িত হয়েছে Future(সম্ভবত কেবলমাত্র সম্পর্কে দরকারী উদাহরণ cancel())। যখন এটি ইতিমধ্যে একটি Future(বা Task) হয় তখন তা কিছুই করে না; যখন এটি একটি coroutine এটা গোপন করে একটি এটা Task

আপনি যদি জানেন যে আপনার কোনও কর্টিন রয়েছে এবং আপনি এটি নির্ধারিত করতে চান, তবে সঠিক API ব্যবহার করা উচিত create_task()। কেবলমাত্র যখন আপনি কল ensure_future()করা উচিত তখন যখন আপনি একটি এপিআই সরবরাহ করেন (অ্যাসিনসিওর বেশিরভাগ নিজস্ব নিজস্ব এপিআইয়ের মতো) যা কোনও কর্টিন বা একটি গ্রহণ করে Futureএবং আপনাকে এটির জন্য কিছু করতে হবে যা আপনার প্রয়োজন Future

এবং পরে:

পরিশেষে আমি এখনও বিশ্বাস করি এটি ensure_future()খুব কম প্রয়োজনীয় কার্যকারিতার টুকরোটির জন্য একটি যথাযথ অস্পষ্ট নাম। কোনও কর্টিন থেকে কোনও কাজ তৈরি করার সময় আপনার যথাযথ-নাম ব্যবহার করা উচিত loop.create_task()। এর জন্য কি কোনও নাম থাকতে হবে asyncio.create_task()?

এটা আমার জন্য অবাক। ensure_futureলুপের সদস্যের সাথে তুলনা করে উচ্চতর স্তরের ফাংশনটি create_task(আলোচনায় যুক্তকরণ বা যুক্ত করার মতো কিছু ধারণাগুলি রয়েছে ) এর সাথে সমস্ত ব্যবহার করার আমার মূল প্রেরণা ছিল ।asyncio.spawnasyncio.create_task

আমি এটিও উল্লেখ করতে পারি যে আমার মতে এটি সর্বজনীন ফাংশনটি ব্যবহার করা বেশ সুবিধাজনক যা Awaitableকেবল কার্টাইনগুলির চেয়ে কোনও হ্যান্ডেল করতে পারে ।

তবে, গিডোর উত্তর পরিষ্কার: "কোনও কর্টিন থেকে কোনও কাজ তৈরি করার সময় আপনার যথাযথ-নাম ব্যবহার করা উচিত loop.create_task()"

কর্টাইনগুলি কখন কার্যগুলিতে আবৃত করা উচিত?

কোনও টাস্কে কর্টিন মোড়ান - "ব্যাকগ্রাউন্ডে" এই কর্টিনটি শুরু করার একটি উপায়। এখানে উদাহরণ:

import asyncio


async def msg(text):
    await asyncio.sleep(0.1)
    print(text)


async def long_operation():
    print('long_operation started')
    await asyncio.sleep(3)
    print('long_operation finished')


async def main():
    await msg('first')

    # Now you want to start long_operation, but you don't want to wait it finised:
    # long_operation should be started, but second msg should be printed immediately.
    # Create task to do so:
    task = asyncio.ensure_future(long_operation())

    await msg('second')

    # Now, when you want, you can await task finised:
    await task


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

আউটপুট:

first
long_operation started
second
long_operation finished

আপনি প্রতিস্থাপন করতে পারেন asyncio.ensure_future(long_operation())শুধু সঙ্গে await long_operation()পার্থক্য অনুভব করতে।


4
গুইডোর মতে, আপনার create_taskযদি সত্যই এএ টাস্ক অবজেক্টের প্রয়োজন হয় তবে আপনার ব্যবহার করা উচিত , যা আপনার সাধারণত প্রয়োজন হয় না: github.com/python/asyncio/issues/477#issuecomment-268709555
bj0

@ বিজে0 এই লিঙ্কটির জন্য আপনাকে ধন্যবাদ। আমি এই আলোচনা থেকে তথ্য যুক্ত উত্তর আপডেট করেছি।
মিখাইল গেরাসিমভ

নেই ensure_futureস্বয়ংক্রিয়ভাবে তৈরি যোগ Taskপ্রধান ঘটনা লুপ কিভাবে?
AlQuemist

@ অ্যালকুইমিস্ট আপনার তৈরি প্রতিটি কর্টিন, ভবিষ্যত বা কার্য স্বয়ংক্রিয়ভাবে কিছু ইভেন্ট লুপের সাথে আবদ্ধ হয়, যেখানে এটি পরে সম্পাদন করা হবে। ডিফল্টরূপে এটি বর্তমান থ্রেডের জন্য বর্তমান ইভেন্ট লুপ, তবে আপনি loopকীওয়ার্ড আর্গুমেন্ট ব্যবহার করে অন্যান্য ইভেন্টের লুপটি নির্দিষ্ট করতে পারেন (নিশ্চিত করুন_ ভবিষ্যতের স্বাক্ষর দেখুন )।
মিখাইল গেরাসিমভ

4
দ্বিতীয় কলটিতে ইভেন্ট লুপে নিয়ন্ত্রণ ফিরিয়ে আনতে আমাদের awaitমধ্যে লেক্যাট দরকার msg()। ইভেন্ট লুপ একবার নিয়ন্ত্রণ পান এটি শুরু করতে সক্ষম হবে long_operation()। এটি প্রদর্শন করার জন্য তৈরি হয়েছিল যে কীভাবে ensure_futureবর্তমান সম্পাদন প্রবাহের সাথে একযোগে কার্যকর করতে কর্টিন শুরু হয়।
মিখাইল গেরাসিমভ

47

create_task()

  • কর্টিন গ্রহণ করে,
  • টাস্ক প্রদান করে,
  • এটি লুপ প্রসঙ্গে অনুরোধ করা হয়।

ensure_future()

  • ফিউচার, কর্টিনস, প্রতীক্ষিত বস্তু গ্রহণ করে
  • কার্য প্রদান করে (বা ভবিষ্যত যদি ভবিষ্যত কেটে যায়)।
  • যদি দেওয়া ARG একটি coroutine এটা ব্যবহার করে create_task,
  • লুপ অবজেক্ট পাস হতে পারে।

আপনি দেখতে পারেন যে create_task আরও নির্দিষ্ট।


async create_task বা নিশ্চিত_ ভবিষ্যত ছাড়াই ফাংশন

সাধারণ আমন্ত্রণমূলক asyncফাংশনটি কর্টিন দেয়

>>> async def doit(i):
...     await asyncio.sleep(3)
...     return i
>>> doit(4)   
<coroutine object doit at 0x7f91e8e80ba0>

এবং যেহেতু gatherহুডের নীচের অংশটি নিশ্চিত করে ( ensure_future) যে আরগগুলি ফিউচার, তাই স্পষ্টতই ensure_futureঅপ্রয়োজনীয়।

অনুরূপ প্রশ্ন লুপ.ক্রিয়েট_টাস্ক, অ্যাসিনসিও.অ্যাসেক / নিশ্চিত_ফিউচার এবং টাস্কের মধ্যে পার্থক্য কী?


14

দ্রষ্টব্য: পাইথন ৩.7 এর জন্য কেবল বৈধ (পাইথন ৩.৫ এর জন্য পূর্ববর্তী উত্তরটি উল্লেখ করুন )।

অফিসিয়াল ডক্স থেকে:

asyncio.create_task(পাইথন ৩.7-এ যোগ করা) এর পরিবর্তে নতুন কার্য সম্পাদনের পক্ষে সর্বোত্তম উপায় ensure_future()


বিস্তারিত:

সুতরাং, পাইথন ৩.7 এর পরের দিকে, শীর্ষস্থানীয় 2 টি শীর্ষ র‌্যাপার ফাংশন রয়েছে (অনুরূপ তবে ভিন্ন):

ঠিক আছে, নিখুঁতভাবে এই দুটি মোড়ক ফাংশন আপনাকে কল করতে সহায়তা করবে BaseEventLoop.create_task। পার্থক্যটি হ'ল ensure_futureযে কোনও awaitableবিষয় গ্রহণ করা এবং আপনাকে এটি ভবিষ্যতে রূপান্তর করতে সহায়তা করে। এবং এছাড়াও আপনি নিজের event_loopপ্যারামিটার সরবরাহ করতে পারেন ensure_future। এবং আপনার যদি সেই দক্ষতার প্রয়োজন হয় বা না নির্ভর করে আপনি কেবল কোন মোড়ক ব্যবহার করবেন তা বেছে নিতে পারেন।


আমি মনে করি যে আরও একটি পার্থক্য রয়েছে যা নথিভুক্ত নয়: আপনি লুপটি চালানোর আগে যদি asyncio.create_task কল করার চেষ্টা করেন, আপনার asyncio.create_task একটি চলমান লুপের প্রত্যাশার পরে সমস্যা হবে। আপনি এই ক্ষেত্রে asyncio.ensure_future ব্যবহার করতে পারেন, তবে, যেহেতু একটি চলমান লুপের প্রয়োজন নেই।
কোয়েলহুডো

4

আপনার উদাহরণস্বরূপ, তিনটি প্রকারই অ্যাসিনক্রোনাসলি কার্যকর করে। পার্থক্যটি হ'ল তৃতীয় উদাহরণে, আপনি সমস্ত 10 কর্টিন তৈরি করেছেন এবং একসাথে লুপটিতে জমা দিয়েছেন। সুতরাং শুধুমাত্র শেষটি এলোমেলোভাবে আউটপুট দেয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.