Penjadwalan
Peringatan
These docs were written for SpongeAPI 7 and are likely out of date. If you feel like you can help update them, please submit a PR!
Spons memperlihatkan :javadoc:`Penjadwal` untuk memungkinkan anda untuk menunjuk tugas-tugas yang akan dieksekusi di masa depan. Yang Penjadwal
menyediakan sebuah :javadoc:`Tugas.Pembangun` dengan mana anda dapat menentukan properti tugas seperti penundaan, selang, nama, (a)sinkronisitas, dan Runnable
(lihat tugas-properti).
Penyusun Halaman
Pertama, mendapatkan contoh dari Tugas.Pembangun
:
import org.spongepowered.api.scheduler.Task;
Task.Builder taskBuilder = Task.builder();
Satu-satunya diharuskan properti ini adalah Runnable, yang mana dapat anda tentukan menggunakan :javadoc:`Tugas.Pembangun#menjalankan(Runnable)`:
taskBuilder.execute(new Runnable() {
public void run() {
logger.info("Yay! Schedulers!");
}
});
atau menggunakan Java 8 sintaks dengan Tugas.Pembangun#menjalankan(Runnable runnable)
taskBuilder.execute(
() -> {
logger.info("Yay! Schedulers!");
}
);
atau menggunakan java 8 sintaks dengan Tugas.Pembangun#menjalankan(Konsumen<Task> tugas)
taskBuilder.execute(
task -> {
logger.info("Yay! Schedulers! :" + task.getName());
}
);
Blok properti
Dengan menggunakan Tugas.Pembangun
, anda dapat menentukan lain, properti opsional, seperti yang dijelaskan di bawah ini.
Properti |
Motede Dipakai |
Deskripsi |
---|---|---|
tundaan |
delayTicks(long delay)
|
Yang opsional jumlah waktu untuk lulus sebelum tugas adalah yang harus menjalankan. Waktu ditentukan sebagai jumlah kutu dengan delayTicks() metode, atau dapat diberikan sebagai jumlah waktu yang lebih nyaman unit dengan menentukan TimeUnit dengan delay() metode. Salah satu metode, tetapi tidak keduanya, dapat ditentukan per tugas. |
selang |
|
Jumlah waktu antara pengulangan tugas. Jika selang waktu tidak ditentukan, tugas tidak akan terulang. Waktu ditentukan sebagai jumlah kutu dengan intervalTicks() metode, atau dapat diberikan sebagai jumlah waktu yang lebih nyaman unit dengan menentukan TimeUnit dengan interval() metode. Salah satu metode, tetapi tidak keduanya, dapat ditentukan per tugas. |
sinkronisasi |
async() |
Sinkron tugas dijalankan dalam permainan ini loop utama di seri dengan centang siklus. Jika |
nama |
name(String name) |
Nama tugas. Secara default, nama tugas akan PLUGIN_ID " - " ( "- "|"S-" ) SERIAL_ID. Misalnya, default nama tugas bisa terlihat seperti "fooplugin-A-12". Ada dua tugas aktif akan memiliki yang sama serial ID yang sama jenis sinkronisasi. Jika nama tugas yang ditentukan, harus deskriptif dan membantu pengguna dalam debugging plugin anda. |
Terakhir, menyerahkan tugas scheduler menggunakan Task.Builder#submit(Object).
Dan hanya itu! Untuk meringkas, sepenuhnya fungsional tugas terjadwal yang akan berjalan asynchronously setiap 5 menit setelah awal keterlambatan dari 100 milidetik bisa dibangun dan disampaikan dengan menggunakan kode berikut:
import java.util.concurrent.TimeUnit;
PluginContainer plugin = ...;
Task task = Task.builder().execute(() -> logger.info("Yay! Schedulers!"))
.async().delay(100, TimeUnit.MILLISECONDS).interval(5, TimeUnit.MINUTES)
.name("ExamplePlugin - Fetch Stats from Database").submit(plugin);
Untuk membatalkan tugas, hanya menyebut :javadoc:`Tugas#batal()` metode:
task.cancel();
If you need to cancel the task from within the runnable itself, you can instead opt to use a Consumer<Task>
in
order to access the task. The below example will schedule a task that will count down from 60 and cancel itself upon
reaching 0.
@Listener
public void onGameInit(GameInitializationEvent event) {
Task task = Task.builder().execute(new CancellingTimerTask())
.interval(1, TimeUnit.SECONDS)
.name("Self-Cancelling Timer Task").submit(plugin);
}
private class CancellingTimerTask implements Consumer<Task> {
private int seconds = 60;
@Override
public void accept(Task task) {
seconds--;
Sponge.getServer()
.getBroadcastChannel()
.send(Component.text("Remaining Time: "+seconds+"s"));
if (seconds < 1) {
task.cancel();
}
}
}
Peringatan
Any scheduled tasks should either watch the current state of the Game or should be unregistered if they are no longer needed (e.g. during a GameStoppingServerEvent). This is of particular importance for the client because it can start and stop the server multiple times.
Asynchronous Tugas
Asynchronous tugas yang harus digunakan terutama untuk kode yang dapat mengambil jangka waktu yang signifikan untuk mengeksekusi, yaitu permintaan ke server lain atau database. Jika dilakukan di thread utama, permintaan ke server lain bisa sangat mempengaruhi kinerja dari permainan, karena berikutnya centang tidak bisa dipecat sampai request selesai.
Since Minecraft is largely single-threaded, there is little you can do in an asynchronous thread. If you must run a thread asynchronously, you should execute all of the code that does not use SpongeAPI/affect Minecraft, then register another synchronous task to handle the code that needs the API. There are a few parts of Minecraft that you can work with asynchronously, including:
Obrolan
Sponge's built-in Permissions penanganan
Sponge's scheduler
Selain itu, ada beberapa operasi lain yang aman untuk melakukan asynchronous:
Jaringan independen permintaan
Filesystem I/O (excluding files used by Sponge)
Peringatan
Mengakses permainan benda-benda di luar thread utama dapat menyebabkan crash, inkonsistensi dan berbagai masalah lainnya dan harus dihindari. Jika hal ini dilakukan salah, anda bisa mendapatkan ConcurrentModificationException dengan atau tanpa kecelakaan server terbaik dan rusak player/dunia/server yang paling buruk.
Peringatan
Any scheduled tasks should either watch the current state of the Game or should be unregistered if they are no longer needed (e.g. during a GameStoppingServerEvent). This is of particular importance for the client because it can start and stop the server multiple times.
Kompatibilitas dengan aturan belanja lainnya
Sebagai plugin anda tumbuh dalam ukuran dan ruang lingkup anda mungkin ingin mulai menggunakan salah satu dari banyak concurrency perpustakaan, tersedia untuk Java dan JVM. Perpustakaan ini memang cenderung mendukung Java ExecutorService sebagai sarana untuk mengarahkan di mana benang tugas dijalankan.
Untuk memungkinkan perpustakaan ini untuk bekerja dengan Spons Scheduler
metode berikut dapat digunakan:
Scheduler#createSyncExecutor(Object) menciptakan :javadoc: SpongeExecutorService yang menjalankan tugas-tugas melalui Spons sinkron scheduler.
Scheduler#createAsyncExecutor(Object) creates a
SpongeExecutorService
which executes tasks through Sponge's asynchronous scheduler. Tasks are subject to the restrictions mentioned in Asynchronous Tasks.
Satu hal yang perlu diingat adalah bahwa tugas-tugas yang berinteraksi dengan Sponge di luar interaksi yang terdaftar di Asynchronous Tugas butuh untuk dieksekusi pada ExecutorService dibuat dengan Scheduler#createSyncExecutor(Objek) untuk menjadi thread-safe.
import org.spongepowered.api.scheduler.SpongeExecutorService;
PluginContainer plugin = ...;
SpongeExecutorService minecraftExecutor = Sponge.getScheduler().createSyncExecutor(plugin);
minecraftExecutor.submit(() -> { ... });
minecraftExecutor.schedule(() -> { ... }, 10, TimeUnit.SECONDS);
Hampir semua perpustakaan memiliki beberapa cara beradaptasi ExecutorService
untuk native jadwal tugas. Sebagai contoh paragraf berikut akan menjelaskan bagaimana ExecutorService
digunakan di sejumlah perpustakaan.
CompletableFuture (Java 8)
Dengan Java 8 CompletableFuture objek ditambahkan ke perpustakaan standar. Dibandingkan dengan ` masa Depan` objek, hal ini memungkinkan bagi pengembang untuk menyediakan callback yang disebut ketika selesai masa depan daripada memblokir benang sampai depan akhirnya selesai.
CompletableFuture adalah menguasai antarmuka yang biasanya memiliki tiga variasi untuk masing-masing fungsinya:
CompletableFuture#<function>Async(..., Executor ex)
Executes this function throughex
CompletableFuture#<function>Async(...)
Executes this function throughForkJoinPool.commonPool()
`` CompletableFuture # <function> (...) `` Jalankan fungsi ini pada thread apa pun yang sebelumnya `` CompletableFuture`` telah selesai.
import java.util.concurrent.CompletableFuture;
PluginContainer plugin = ...;
SpongeExecutorService minecraftExecutor = Sponge.getScheduler().createSyncExecutor(plugin);
CompletableFuture.supplyAsync(() -> {
// ASYNC: ForkJoinPool.commonPool()
return 42;
}).thenAcceptAsync((awesomeValue) -> {
// SYNC: minecraftExecutor
}, minecraftExecutor).thenRun(() -> {
// SYNC: minecraftExecutor
});
RxJava
`RxJava <https://github.com/ReactiveX/RxJava> ` _ adalah implementasi dari konsep `Reactive Extensions <http://reactivex.io/> ` _ untuk JVM.
Multithreading di Rx dikelola melalui berbagai Schedulers <http://reactivex.io/documentation/scheduler.html> ` _. Menggunakan ` Penjadwal # dari (Pelaksana Pelaksana) `` fungsi `` Pelaksana` yang disediakan oleh Sponge dapat diubah menjadi Penjadwal `` `.
Seperti CompletableFuture
secara default tindakan yang dilaksanakan pada benang yang sama yang melengkapi verifikasi identitas sebelumnya bagian dari rantai. Gunakan yang dapat Diamati#observeOn(Scheduler scheduler) untuk bergerak di antara benang.
Salah satu hal yang penting untuk diingat adalah bahwa akar Observable
akan dipanggil pada apa pun benang Observable#subscribe()``dipanggil. Jika akar dapat diamati berinteraksi dengan sponge itu harus dipaksa untuk berjalan serempak menggunakan ``Observable#subscribeOn(Scheduler scheduler)
.
import rx.Observable;
import rx.Scheduler;
import rx.schedulers.Schedulers;
PluginContainer plugin = ...;
SpongeExecutorService executor = Sponge.getScheduler().createSyncExecutor(plugin);
Scheduler minecraftScheduler = Schedulers.from(executor);
Observable.defer(() -> Observable.from(Sponge.getServer().getOnlinePlayers()))
.subscribeOn(minecraftScheduler) // defer -> SYNC: minecraftScheduler
.observeOn(Schedulers.io()) // -> ASYNC: Schedulers.io()
.filter(player -> {
// ASYNC: Schedulers.io()
return "Flards".equals(player.getName());
})
.observeOn(minecraftScheduler) // -> SYNC: minecraftScheduler
.subscribe(player -> {
// SYNC: minecraftScheduler
player.kick(Component.text("Computer says no"));
});
Scala
Scala comes with a built-in Future object which a lot of scala framework mirror in design. Most methods of the Future accept an ExecutionContext which determined where that part of the operation is executed. This is different from the CompletableFuture or RxJava since they default to executing on the same thread on which the previous operation ended.
The fact that all these operations try to implicitly find an ExecutionContext
means that you can easily use
the default ExecutionContext.global
and specifically run the parts that need to be thread-safe on the Sponge
server thread.
Untuk menghindari sengaja penjadwalan pekerjaan melalui Sponsge ExecutorContext
konteks lain harus secara implisit didefinisikan sehingga bertindak sebagai pilihan default. Untuk menjaga keselamatan thread hanya fungsi yang benar-benar berinteraksi dengan Spons akan perlu untuk memiliki Spons pelaksana yang ditentukan.
import scala.concurrent.ExecutionContext
val executor = Sponge.getScheduler().createSyncExecutor(plugin)
import ExecutionContext.Implicits.global
val ec = ExecutionContext.fromExecutorService(executor)
val future = Future {
// ASYNC: ExecutionContext.Implicits.global
}
future foreach {
case value => // SYNC: ec
}(ec)
future map {
case value => 42 // SYNC: ec
}(ec).foreach {
case value => println(value) // ASYNC: ExecutionContext.Implicits.global
}